From daac4b157caa1f9228814a7e0e6e56144998501f Mon Sep 17 00:00:00 2001 From: Peter Staab Date: Tue, 27 May 2025 08:00:57 -0400 Subject: [PATCH] Restructure the POD of macros For consistency the POD of macros have been updated so that there is a `=HEAD1 NAME` with the following structure: ``` macroName.pl - short description. ``` --- macros/answers/ConditionalHint.pl | 22 +- macros/answers/Generic.pl | 93 ++++--- macros/answers/PGasu.pl | 81 ++---- macros/answers/PGfunctionevaluators.pl | 57 ++--- macros/answers/PGmiscevaluators.pl | 15 +- macros/answers/PGstringevaluators.pl | 103 ++++---- macros/answers/answerComposition.pl | 2 +- macros/answers/answerCustom.pl | 43 ++-- macros/answers/answerHints.pl | 14 +- macros/answers/answerVariableList.pl | 9 +- macros/answers/extraAnswerEvaluators.pl | 8 +- macros/answers/unorderedAnswer.pl | 4 +- macros/contexts/contextABCD.pl | 4 + macros/contexts/contextAlternateDecimal.pl | 14 +- macros/contexts/contextAlternateIntervals.pl | 29 +-- macros/contexts/contextArbitraryString.pl | 35 ++- macros/contexts/contextBaseN.pl | 13 +- macros/contexts/contextBoolean.pl | 16 +- macros/contexts/contextComplexExtras.pl | 44 ++-- macros/contexts/contextComplexJ.pl | 48 +--- macros/contexts/contextCongruence.pl | 37 +-- macros/contexts/contextCurrency.pl | 94 +++---- macros/contexts/contextExtensions.pl | 231 ++++++++---------- macros/contexts/contextFiniteSolutionSets.pl | 53 ++-- macros/contexts/contextForm.pl | 16 +- macros/contexts/contextFraction.pl | 222 +++++------------ macros/contexts/contextFunctionAssign.pl | 21 +- macros/contexts/contextInequalities.pl | 140 ++++------- .../contextInequalitiesAllowStrings.pl | 18 +- .../contexts/contextInequalitySetBuilder.pl | 83 ++----- macros/contexts/contextInteger.pl | 58 +++-- macros/contexts/contextIntegerFunctions.pl | 4 +- macros/contexts/contextLeadingZero.pl | 12 + macros/contexts/contextLimitedComplex.pl | 69 +----- macros/contexts/contextLimitedFactor.pl | 14 +- macros/contexts/contextLimitedNumeric.pl | 11 +- macros/contexts/contextLimitedPoint.pl | 38 +-- macros/contexts/contextLimitedPolynomial.pl | 79 ++---- macros/contexts/contextLimitedPowers.pl | 12 +- macros/contexts/contextLimitedRadical.pl | 62 ++--- .../contexts/contextLimitedRadicalComplex.pl | 13 +- macros/contexts/contextLimitedVector.pl | 56 +---- macros/contexts/contextMatrixExtras.pl | 20 +- macros/contexts/contextOrdering.pl | 49 +--- macros/contexts/contextPartition.pl | 53 ++-- macros/contexts/contextPercent.pl | 80 ++---- macros/contexts/contextPermutation.pl | 40 +-- macros/contexts/contextPermutationUBC.pl | 4 +- macros/contexts/contextPiecewiseFunction.pl | 30 +-- macros/contexts/contextPolynomialFactors.pl | 24 +- macros/contexts/contextRationalExponent.pl | 21 +- macros/contexts/contextRationalFunction.pl | 21 +- macros/contexts/contextReaction.pl | 173 ++++--------- macros/contexts/contextRestrictedDomains.pl | 15 +- macros/contexts/contextScientificNotation.pl | 73 ++---- macros/contexts/contextString.pl | 6 - macros/contexts/contextTrigDegrees.pl | 32 +-- macros/contexts/contextTypeset.pl | 3 + macros/contexts/legacyFraction.pl | 3 + macros/core/PGML.pl | 60 ++--- macros/core/PGanswermacros.pl | 2 + macros/core/PGauxiliaryFunctions.pl | 47 ++-- macros/core/PGbasicmacros.pl | 2 +- macros/core/PGcommonFunctions.pl | 23 +- macros/core/PGgraders.pl | 10 +- macros/core/Value.pl | 20 +- macros/core/externalData.pl | 4 +- macros/core/sage.pl | 2 +- macros/deprecated/PGcomplexmacros.pl | 3 +- macros/deprecated/PGcomplexmacros2.pl | 4 +- macros/deprecated/PGsequentialmacros.pl | 5 +- macros/deprecated/weightedGrader.pl | 6 +- .../graph/LiveGraphicsParametricSurface3D.pl | 2 +- macros/graph/PGanalyzeGraph.pl | 9 +- macros/graph/PGgraphgrid.pl | 7 +- macros/graph/PGgraphmacros.pl | 86 ++----- macros/graph/PGlateximage.pl | 2 - macros/graph/PGnauGraphics.pl | 2 + macros/graph/PGstatisticsGraphMacros.pl | 26 +- macros/graph/PGtikz.pl | 2 - macros/graph/imageChoice.pl | 21 +- macros/graph/plotly3D.pl | 5 +- macros/graph/unionImage.pl | 2 + macros/math/MatrixCheckers.pl | 32 +-- macros/math/MatrixReduce.pl | 41 +--- macros/math/MatrixUnimodular.pl | 230 +++++++++-------- macros/math/MatrixUnits.pl | 37 +-- macros/math/PCCfactor.pl | 85 ++++--- macros/math/PGdiffeqmacros.pl | 6 +- macros/math/PGmatrixmacros.pl | 3 +- macros/math/PGmorematrixmacros.pl | 9 +- macros/math/PGnauBinpacking.pl | 9 + macros/math/PGnauGraphCatalog.pl | 8 + macros/math/PGnauGraphtheory.pl | 9 +- macros/math/PGnauScheduling.pl | 8 + macros/math/PGnauSet.pl | 9 + macros/math/PGnauStats.pl | 9 + macros/math/PGnumericalmacros.pl | 34 +-- macros/math/PGpolynomialmacros.pl | 8 +- macros/math/PGstatisticsmacros.pl | 220 ++++++++++------- macros/math/SI_property_tables.pl | 9 + macros/math/SolveLinearEquationPCC.pl | 9 + .../SystemsOfLinearEquationsProblemPCC.pl | 15 +- macros/math/VectorListCheckers.pl | 11 +- macros/math/algebraMacros.pl | 126 +++++++--- macros/math/customizeLaTeX.pl | 5 +- macros/math/draggableProof.pl | 18 +- macros/math/draggableSubsets.pl | 9 +- macros/math/fixedPrecision.pl | 9 + macros/math/interpMacros.pl | 11 +- macros/math/specialTrigValues.pl | 6 +- macros/math/tableau_main_subroutines.pl | 8 + macros/misc/PGunion.pl | 1 + macros/misc/unionMacros.pl | 2 + macros/misc/unionMessages.pl | 2 + macros/misc/unionProblem.pl | 2 +- macros/misc/unionUtils.pl | 2 + macros/parsers/parserDifferenceQuotient.pl | 2 +- macros/parsers/parserFormulaUpToConstant.pl | 95 +++---- macros/parsers/parserFormulaWithUnits.pl | 13 +- macros/parsers/parserLinearRelation.pl | 27 +- macros/parsers/parserMultiAnswer.pl | 59 ++--- macros/parsers/parserNumberWithUnits.pl | 10 +- macros/parsers/parserOneOf.pl | 38 +-- macros/parsers/parserParametricLine.pl | 20 +- macros/parsers/parserWordCompletion.pl | 4 +- macros/ui/PGchoicemacros.pl | 112 +++------ macros/ui/PGinfo.pl | 19 +- macros/ui/alignedChoice.pl | 2 + macros/ui/choiceUtils.pl | 2 + macros/ui/niceTables.pl | 13 +- macros/ui/quickMatrixEntry.pl | 2 + macros/ui/source.pl | 8 +- macros/ui/text2PG.pl | 2 +- macros/ui/unionLists.pl | 2 + macros/ui/unionTables.pl | 1 + 136 files changed, 1809 insertions(+), 2620 deletions(-) diff --git a/macros/answers/ConditionalHint.pl b/macros/answers/ConditionalHint.pl index 9561ee225b..e9cc47bbcd 100644 --- a/macros/answers/ConditionalHint.pl +++ b/macros/answers/ConditionalHint.pl @@ -1,12 +1,10 @@ -=head1 ConditionalHint.pl +=head1 NAME -=head2 NAME - -C - Allows a hint to be revealed after a student +ConditionalHint.pl - Allows a hint to be revealed after a student has entered an answer correctly. -=head2 DESCRIPTION +=head1 DESCRIPTION The subroutine C allows a hint to be revealed after a student has entered an answer correctly. It is useful @@ -17,9 +15,9 @@ =head2 DESCRIPTION A subroutine C that returns 0 or 1 is also provided. -=head2 USAGE +=head1 MACROS -=head3 Synopsis of ConditionalHint +=head2 ConditionalHint loadMacros("ConditionalHint.pl"); @@ -102,10 +100,6 @@ =head3 Complete Working Example of ConditionalHint ENDDOCUMENT(); -=head2 AUTHOR - -Paul Pearson - =cut sub _ConditionalHint_init { }; # don't reload this file @@ -142,14 +136,8 @@ sub IsAnswerCorrect { @_ ); - # my $name_of_correct_answer = shift; - # my $answer_rule_number = shift; - - # return $name_of_correct_answer->cmp()->evaluate($inputs_ref->{ANS_NUM_TO_NAME($answer_rule_number)})->{score}; - return $options{ans_name}->cmp()->evaluate($inputs_ref->{ ANS_NUM_TO_NAME($options{ans_number}) })->{score}; } 1; - diff --git a/macros/answers/Generic.pl b/macros/answers/Generic.pl index 6e52d12125..7b0ad5d209 100644 --- a/macros/answers/Generic.pl +++ b/macros/answers/Generic.pl @@ -1,30 +1,28 @@ -#R. Byerly, Texas Tech University, 2005 -sub _Generic { } #Don't reload this file. +=head1 NAME -#Documentation: +Generic.pl - provide some generic answer checkers. -=head1 Generic Answer Checker +=head1 DESCRIPTION -(Based on David Cervone's vector_cmp. See -doc/parser/extensions/8-answer.pg under the webwork2 directory.) -Place in macros directory and load this file (Generic.pl) using the -loadMacros command. (To just copy it into a pg file, replace -occurences of "\&" by "~~&".) +This macro provides a set of functions that provide a generic answer checker. - Usage: +Usage: + + ANS( generic_cmp(, ) ); - ANS( generic_cmp(, ) ); where is a parser object or syntactically correct string for a parser object. Mandatory arguments: - type => + type => + where is a recognized parser type (e.g., Number, Point, Vector, Matrix, etc.) - checker => + checker => + where is a reference to a subroutine that will be passed (in order) the parsed (and, if possible, evaluated) student answer, the parsed professor's answer, and a reference to the answer hash. (The @@ -33,62 +31,55 @@ =head1 Generic Answer Checker Optional arguments: - correct_ans => + correct_ans => + where is a string that will show up as the correct answer when solutions are available. - variables_allowed => 0 or 1 + variables_allowed => 0 or 1 + (default 0 (false). Determines whether student's answer is allowed to contain variables. In this case the checker must take care of evaluating it.) - length => n + length => n + where n is the number of elements in an expected answer of type list, vector, or points. Returns error message to student if answer of wrong length is entered. +=head1 SYNOPSIS -####################Example:########################## -DOCUMENT(); # This should be the first executable line in the problem. + DOCUMENT(); -loadMacros( -"PG.pl", -"PGbasicmacros.pl", -"PGanswermacros.pl", -"Parser.pl", -"Generic.pl", -); + loadMacros("PG.pl", "PGbasicmacros.pl", "PGanswermacros.pl", "Parser.pl", "Generic.pl"); -TEXT(&beginproblem); + Context("Vector"); + $A=Vector(1,2,1); + $B=Vector(1,3,1); + $C=Vector(1,4,1); -Context("Vector"); -$A=Vector(1,2,1); -$B=Vector(1,3,1); -$C=Vector(1,4,1); + BEGIN_TEXT + Show that the vectors \(\{$A->TeX\}, \{$B->TeX\}, \{$C->TeX\}\) do + not span \(R^3\) by giving a vector not in their span: + \{ans_rule()\} + END_TEXT -BEGIN_TEXT -Show that the vectors \(\{$A->TeX\}, \{$B->TeX\}, \{$C->TeX\}\) do -not span \(R^3\) by giving a vector not in their span: -\{ans_rule()\} -END_TEXT + sub check { + my $stu=shift; + $x1=$stu->extract(1); $x3=$stu->extract(3); + $x1 != $x3; #any vectors with different 1st and 3rd coordinates + } -#Easy to get by guessing! - -sub check{ - my $stu=shift(); - $x1=$stu->extract(1); $x3=$stu->extract(3); - $x1 != $x3; #any vectors with different 1st and 3rd coordinates -} + ANS(generic_cmp("23",type => 'Vector', length => 3, checker => ~~&check)); -ANS(generic_cmp("23",type => 'Vector', length => 3, checker => ~~&check)); + ENDDOCUMENT(); -ENDDOCUMENT(); # This should be the last executable line in the problem. - -####################End of Example######################## +=head1 MACROS =cut -#End of Documentation +sub _Generic_init { } # don't reload this file. #From parserUtils.pl: sub protectHTML { @@ -100,6 +91,10 @@ sub protectHTML { } +=head2 generic_cmp + +=cut + sub generic_cmp { my $v = shift; my %opts = @_; @@ -120,6 +115,10 @@ sub generic_cmp { return $ans; } +=head2 generic_cmp_check + +=cut + sub generic_cmp_check { my $ans = shift; my $type = $ans->{type}; diff --git a/macros/answers/PGasu.pl b/macros/answers/PGasu.pl index 3c4c764c5c..13c4528c8e 100644 --- a/macros/answers/PGasu.pl +++ b/macros/answers/PGasu.pl @@ -1,16 +1,13 @@ -### =head1 NAME -PGasu.pl -- located in the pg/macros directory +PGasu.pl -- A set of macros for old school answer checkers. -=head1 SYNPOSIS +=head1 DESCRIPTION -Macros contributed by John Jones +A set of macros for old school answer checkers. -=cut - -# Answer evaluator which always marks things correct +=head1 MACROS =head2 auto_right() @@ -47,6 +44,10 @@ sub auto_right { return $answerEvaluator; } +=head2 auto_right_checker + +=cut + # used in auto_right above # ^function auto_right_checker @@ -56,7 +57,7 @@ sub auto_right_checker { return ($ans); } -=head2 C +=head2 no_decs Can be wrapped around an numerical evaluation. It marks the answer wrong if it contains a decimal point. Usage: @@ -82,7 +83,7 @@ sub no_decs { return $old_evaluator; } -=head2 C +=head2 must_include Wrapper for other answer evaluators. It insists that a string is part of the answer to be marked right. @@ -103,7 +104,7 @@ sub must_include { return $old_evaluator; } -=head2 no_trig_fun() +=head2 no_trig_fun Wrapper for other answer evaluators. It marks the answer wrong if it contains one of the six basic trig functions. @@ -137,9 +138,7 @@ sub no_trig_fun { return $new_eval; } -=head2 no_trig() - - +=head2 no_trig =cut @@ -162,9 +161,7 @@ sub no_trig { return $new_eval; } -=head2 exact_no_trig() - - +=head2 exact_no_trig =cut @@ -187,9 +184,7 @@ sub exact_no_trig { return $new_eval; } -=head2 must_have_filter() - -=pod +=head2 must_have_filter Filter for checking that an answer has (or doesn't have) a certain string in it. This can be used to screen answers where you want them @@ -264,7 +259,7 @@ sub must_have_filter { return $newfilt; } -=head2 catch_errors_filter() +=head2 catch_errors_filter() =cut @@ -282,9 +277,7 @@ sub catch_errors_filter { $rh_ans; } -=head2 raw_student_answer_filter() - - +=head2 raw_student_answer_filter =cut @@ -299,9 +292,7 @@ sub raw_student_answer_filter { return $rh_ans; } -=head2 no_decimal_list() - - +=head2 no_decimal_list =cut @@ -333,9 +324,7 @@ sub no_decimal_list { return $answer_evaluator; } -=head2 no_decimals() - - +=head2 no_decimals =cut @@ -367,15 +356,12 @@ sub no_decimals { return $answer_evaluator; } -=head2 with_comments() - +=head2 with_comments - # Wrapper for an answer evaluator which can also supply comments +Wrapper for an answer evaluator which can also supply comments =cut -# Wrapper for an answer evaluator which can also supply comments - # ^function with_comments sub with_comments { my ($old_evaluator, $cmt) = @_; @@ -406,21 +392,15 @@ sub with_comments { $ans_evaluator; } -=head2 pc_evaluator() - - - # Wrapper for multiple answer evaluators, it takes a list of the following as inputs - # [answer_evaluator, partial credit factor, comment] - # it applies evaluators from the list until it hits one with positive credit, - # weights it by the partial credit factor, and throws in its comment +=head2 pc_evaluator +Wrapper for multiple answer evaluators, it takes a list of the following as inputs +[answer_evaluator, partial credit factor, comment] +it applies evaluators from the list until it hits one with positive credit, +weights it by the partial credit factor, and throws in its comment =cut -# Wrapper for multiple answer evaluators, it takes a list of the following as inputs -# [answer_evaluator, partial credit factor, comment] -# it applies evaluators from the list until it hits one with positive credit, -# weights it by the partial credit factor, and throws in its comment # ^function pc_evaluator sub pc_evaluator { my @ev_list; @@ -462,15 +442,13 @@ sub pc_evaluator { $ans_evaluator; } -=head2 weighted_partial_grader - -=pod +=head2 weighted_partial_grader This is a grader which weights the different parts of the problem differently. The weights passed to it through the environment. In the problem: - $ENV{'partial_weights'} = [.2,.2,.2,.3]; + $ENV{'partial_weights'} = [.2,.2,.2,.3]; This will soon be superceded by a better grader. @@ -549,8 +527,3 @@ sub weighted_partial_grader { } 1; - -## Local Variables: -## mode: CPerl -## font-lock-mode: t -## End: diff --git a/macros/answers/PGfunctionevaluators.pl b/macros/answers/PGfunctionevaluators.pl index 8a87a299a8..c7ace71802 100644 --- a/macros/answers/PGfunctionevaluators.pl +++ b/macros/answers/PGfunctionevaluators.pl @@ -1,21 +1,10 @@ +## Note: this should be decprecated + =head1 NAME PGfunctionevaluators.pl - Macros that generate function answer evaluators. -=head1 SYNOPSIS - - ANS(fun_cmp($answer_or_answer_array_ref, %options)); - - ANS(function_cmp($correctEqn, $var, $llimit, $ulimit, $relTol, $numPoints, $zeroLevel, - $zeroLevelTol)); - ANS(function_cmp_up_to_constant($correctEqn, $var, $llimit, $ulimit, $relpercentTol, - $numOfPoints, $maxConstantOfIntegration, $zeroLevel, - $zeroLevelTol)); - ANS(function_cmp_abs($correctFunction, $var, $llimit, $ulimit, $absTol, $numOfPoints)); - ANS(function_cmp_up_to_constant_abs($correctFunction, $var, $llimit, $ulimit, - $absTol, $numOfPoints, $maxConstantOfIntegration)); - =head1 DESCRIPTION Function answer evaluators take in a function, compare it numerically to a @@ -27,12 +16,17 @@ =head1 DESCRIPTION options as parameters. There are also several specific function_cmp_*() answer evaluators for use in common situations which feature a simplified syntax. -=head2 MathObjects and answer evaluators +=head1 SYNOPSIS -The MathObjects system provides a Formula->cmp() method that produce answer -evaluators for function comparisons. fun_cmp() has been rewritten to use -Formula->cmp() to produce the answer evaluator. It is recommended that you use -the Formula object's cmp() method directly if possible. + ANS(fun_cmp($answer_or_answer_array_ref, %options)); + ANS(function_cmp($correctEqn, $var, $llimit, $ulimit, $relTol, $numPoints, $zeroLevel, + $zeroLevelTol)); + ANS(function_cmp_up_to_constant($correctEqn, $var, $llimit, $ulimit, $relpercentTol, + $numOfPoints, $maxConstantOfIntegration, $zeroLevel, + $zeroLevelTol)); + ANS(function_cmp_abs($correctFunction, $var, $llimit, $ulimit, $absTol, $numOfPoints)); + ANS(function_cmp_up_to_constant_abs($correctFunction, $var, $llimit, $ulimit, + $absTol, $numOfPoints, $maxConstantOfIntegration)); =cut @@ -75,15 +69,16 @@ sub _PGfunctionevaluators_init { } } -=head1 fun_cmp +=head1 MACROS +=head2 fun_cmp - ANS(fun_cmp($answer_or_answer_array_ref, %options)); + ANS(fun_cmp($answer_or_answer_array_ref, %options)); Compares a function or a list of functions, using a named hash of options to set parameters. This can make for more readable code than using the function_cmp() style, but some people find one or the other easier to remember. -=head2 Options +=head3 Options $answer_or_answer_array_ref can either be a string scalar representing the correct formula or a reference to an array of string scalars. If multiple @@ -130,7 +125,7 @@ =head2 Options result of evaluation at each point must be within 1% of the correct answer to qualify as correct. In other words, a student answer is correct when - abs(studentAnswer - correctAnswer) <= abs(.01*relTol*correctAnswer) + abs(studentAnswer - correctAnswer) <= abs(.01*relTol*correctAnswer) tol and relTol are mutually exclusive. reltol is also accpeted as a synonym for relTol. @@ -185,13 +180,13 @@ =head2 Options each array corresponding to the lower and upper endpoints of the (half-open) domain of one variable. For example, - vars=>2, limits=>[[0,2], [-3,8]] + vars=>2, limits=>[[0,2], [-3,8]] would cause x to be evaluated in [0,2) and y to be evaluated in [-3,8). If only one variable is being used, you can write either: - limits => [[0,3]] - limits => [0,3] + limits => [[0,3]] + limits => [0,3] domain is recognized as a synonym for limits. @@ -201,18 +196,18 @@ =head2 Options particular function. For example, if you want to use only integer values, they can be specified. With one variable, either of these two forms work: - test_points=>[1,4,5,6] - test_points=>[[1,4,5,6]] + test_points=>[1,4,5,6] + test_points=>[[1,4,5,6]] With more variables, specify the list for the first variable, then the second, and so on: - vars=>['x','y'], test_points=>[[1,4,5],[7,14,29]]". + vars=>['x','y'], test_points=>[[1,4,5],[7,14,29]]". If the problem writer wants random values which need to meet some special restrictions (such as being integers), they can be generated in the problem: - test_points=>[random(1,50), random(1,50), random(1,50), random(1,50)] + test_points=>[random(1,50), random(1,50), random(1,50), random(1,50)] Note that test_points should not be used for function checks which involve parameters (either explicitly given by "params", or as antiderivatives). @@ -238,7 +233,7 @@ =head2 Options =back -=head2 Examples +=head3 Examples # standard compare, variable is x fun_cmp("3*x"); @@ -546,8 +541,6 @@ sub adaptive_function_cmp { ); } -=head1 Multi-variable Function Comparisons - =head2 [DEPRECATED] multivar_function_cmp ANS(multivar_function_cmp($correctFunction, $var, $limits, $relTol, $numPoints, $zeroLevel, $zeroLevelTol)); diff --git a/macros/answers/PGmiscevaluators.pl b/macros/answers/PGmiscevaluators.pl index 782a34d05c..83f21f4aef 100644 --- a/macros/answers/PGmiscevaluators.pl +++ b/macros/answers/PGmiscevaluators.pl @@ -1,3 +1,4 @@ +# Note: this should be deprecated =head1 NAME @@ -7,18 +8,14 @@ =head1 DESCRIPTION Currently contains answer evaluators for radio buttons and checkboxes. -=head2 MathObjects and answer evaluators - -The MathObjects system provides a parserRadioButtons.pl file that manages -display and checking of radio-button based answers. It is recommended that you -use this method directly if possible. - =cut BEGIN { strict->import; } sub _PGmiscevaluators_init { } -=head1 checkbox_cmp +=head1 MACROS + +=head2 checkbox_cmp ANS(checkbox_cmp($correctAnswer)) @@ -83,7 +80,7 @@ sub checkbox_cmp { return $answer_evaluator; } -=head1 radio_cmp +=head2 radio_cmp ANS(radio_cmp($correctAnswer)) @@ -107,7 +104,7 @@ sub radio_cmp { str_cmp($response); } -=head1 SEE ALSO +=head3 SEE ALSO L, L. diff --git a/macros/answers/PGstringevaluators.pl b/macros/answers/PGstringevaluators.pl index c460e6ae5e..d2883c55cb 100644 --- a/macros/answers/PGstringevaluators.pl +++ b/macros/answers/PGstringevaluators.pl @@ -1,3 +1,4 @@ +# Note: this should be deprecated. =head1 NAME @@ -13,18 +14,14 @@ =head1 DESCRIPTION String answer evaluators compare a student string to the correct string. -=head2 MathObjects and answer evaluators - -The MathObjects system provides a String->cmp() method that produce answer -evaluators for string comparisons. It is recommended that you use the String -object's cmp() method directly if possible. - =cut BEGIN { strict->import; } sub _PGstringevaluators_init { } -=head1 String Filters +=head1 MACROS + +=head2 str_filters Different filters can be applied to allow various degrees of variation. Both the student and correct answers are subject to the same filters, to ensure that @@ -71,14 +68,12 @@ sub str_filters { return $rh_ans->{student_ans}; } -=over - -=item remove_whitespace +=head2 remove_whitespace Removes all whitespace from the string. It applies the following substitution to the string: - $filteredAnswer =~ s/\s+//g; + $filteredAnswer =~ s/\s+//g; =cut @@ -91,14 +86,14 @@ sub remove_whitespace { return $rh_ans; } -=item compress_whitespace +=head2 compress_whitespace Removes leading and trailing whitespace, and replaces all other blocks of whitespace by a single space. Applies the following substitutions: - $filteredAnswer =~ s/^\s*//; - $filteredAnswer =~ s/\s*$//; - $filteredAnswer =~ s/\s+/ /g; + $filteredAnswer =~ s/^\s*//; + $filteredAnswer =~ s/\s*$//; + $filteredAnswer =~ s/\s+/ /g; =cut @@ -116,12 +111,12 @@ sub compress_whitespace { return $rh_ans; } -=item trim_whitespace +=head2 trim_whitespace Removes leading and trailing whitespace. Applies the following substitutions: - $filteredAnswer =~ s/^\s*//; - $filteredAnswer =~ s/\s*$//; + $filteredAnswer =~ s/^\s*//; + $filteredAnswer =~ s/\s*$//; =cut @@ -137,7 +132,7 @@ sub trim_whitespace { return $rh_ans; } -=item nullify +=head2 nullify Returns the null string. @@ -152,12 +147,12 @@ sub nullify { return $rh_ans; } -=item ignore_case +=head2 ignore_case Ignores the case of the string. More accurately, it converts the string to uppercase (by convention). Applies the following function: - $filteredAnswer = uc($filteredAnswer); + $filteredAnswer = uc($filteredAnswer); =cut @@ -170,14 +165,14 @@ sub ignore_case { return $rh_ans; } -=item ignore_order +=head2 ignore_order Ignores the order of the letters in the string. This is used for problems of the form "Choose all that apply." Specifically, it removes all whitespace and lexically sorts the letters in ascending alphabetical order. Applies the following functions: - $filteredAnswer = join("", lex_sort(split(/\s*/, $filteredAnswer))); + $filteredAnswer = join("", lex_sort(split(/\s*/, $filteredAnswer))); =cut @@ -193,10 +188,10 @@ sub ignore_order { =back -=head1 str_cmp +=head2 str_cmp - ANS(str_cmp($answer_or_answer_array_ref, @filters)); - ANS(str_cmp($answer_or_answer_array_ref, %options)); + ANS(str_cmp($answer_or_answer_array_ref, @filters)); + ANS(str_cmp($answer_or_answer_array_ref, %options)); Compares a string or a list of strings, using a named hash of options to set parameters. This can make for more readable code than using the "mode"_str_cmp() @@ -211,7 +206,7 @@ =head1 str_cmp checked for. If these strings are found in the argument list, it is assumed that %options is present rather than @filters. -%options can contain the following items: +=head3 options =over @@ -233,7 +228,7 @@ =head1 str_cmp ANS(str_cmp($ans, 'remove_whitespace', 'ignore_order')); ANS(str_cmp($ans, filters=>['remove_whitespace', 'ignore_order'])); -=head2 Examples +=head3 Examples # same as std_str_cmp() -- matches "Hello", " hello", etc. str_cmp("Hello") @@ -312,66 +307,62 @@ sub str_cmp { return (wantarray) ? @output_list : $output_list[0]; } -=head1 "mode"_str_cmp functions +=head2 std_str_cmp The functions of the form "mode"_str_cmp() use different functions to specify which filters to apply. They take no options except the correct string. There are also versions which accept a list of strings. -=over - -=item standard - - std_str_cmp($correctString) - std_str_cmp_list(@correctStringList) + std_str_cmp($correctString) + std_str_cmp_list(@correctStringList) Filters: compress_whitespace, ignore_case -=item standard, case sensitive +=head2 std_cs_str_cmp + +standard, case sensitive - std_cs_str_cmp($correctString) - std_cs_str_cmp_list(@correctStringList) + std_cs_str_cmp($correctString) + std_cs_str_cmp_list(@correctStringList) Filters: compress_whitespace -=item strict +=head2 strict_str_cmp - strict_str_cmp($correctString) - strict_str_cmp_list(@correctStringList) + strict_str_cmp($correctString) + strict_str_cmp_list(@correctStringList) Filters: trim_whitespace -=item unordered +=head2 unordered_str_cmp - unordered_str_cmp( $correctString ) - unordered_str_cmp_list( @correctStringList ) + unordered_str_cmp( $correctString ) + unordered_str_cmp_list( @correctStringList ) Filters: ignore_order, ignore_case -=item unordered, case sensitive +=head2 unordered_cs_str_cmp - unordered_cs_str_cmp( $correctString ) - unordered_cs_str_cmp_list( @correctStringList ) + unordered_cs_str_cmp( $correctString ) + unordered_cs_str_cmp_list( @correctStringList ) Filters: ignore_order -=item ordered +=head2 ordered_str_cmp, ordered_str_cmp_list - ordered_str_cmp( $correctString ) - ordered_str_cmp_list( @correctStringList ) + ordered_str_cmp( $correctString ) + ordered_str_cmp_list( @correctStringList ) Filters: remove_whitespace, ignore_case -=item ordered, case sensitive +=head2 ordered_cs_str_cmp, ordered_cs_str_cmp_list - ordered_cs_str_cmp( $correctString ) - ordered_cs_str_cmp_list( @correctStringList ) + ordered_cs_str_cmp( $correctString ) + ordered_cs_str_cmp_list( @correctStringList ) Filters: remove_whitespace -=back - -=head2 Examples +=head3 Examples # Accepts "W. Mozart", "W. MOZarT", and so forth. Case insensitive. All # internal spaces treated as single spaces. diff --git a/macros/answers/answerComposition.pl b/macros/answers/answerComposition.pl index 4eeebf625e..37a6429aba 100644 --- a/macros/answers/answerComposition.pl +++ b/macros/answers/answerComposition.pl @@ -6,7 +6,7 @@ =head1 NAME =head1 DESCRIPTION -answerComposition.pl provides an answer checker that determines if two functions +This macro provides an answer checker that determines if two functions compose to form a given function. This can be used in problems where you ask a student to break a given function into a composition of two simpler functions, neither of which is allowed to be the identity function. diff --git a/macros/answers/answerCustom.pl b/macros/answers/answerCustom.pl index 331a0fdb95..0a74bfaf0f 100644 --- a/macros/answers/answerCustom.pl +++ b/macros/answers/answerCustom.pl @@ -1,8 +1,15 @@ =head1 NAME -answerCustom.pl - An easy method for creating answer checkers with a custom -subroutine that performs the check for correctness. +answerCustom.pl - provides custom answer checkers + +=cut + +=head1 DESCRIPTION + +This macro provides methods for creating answer checkers with a custom +subroutine that performs the check for correctness. A similar method is provided +for lists. =cut @@ -31,25 +38,17 @@ =head2 custom_cmp =item S 0 or 1 >>> -If 1 (the default), only call the -custom checker if the student answer -is the same object class as the correct -answer (e.g., both are points). -If 0, the checker will be called -whenever the student answer passes -the typeMatch check for the correct -answer. For example, if the correct -answer is a vector, and promotePoints -has been set to 1, then the checker -will be called when the student answer -is a vector OR a point. +If 1 (the default), only call the custom checker if the student answer +is the same object class as the correct answer (e.g., both are points). +If 0, the checker will be called whenever the student answer passes +the typeMatch check for the correct answer. For example, if the correct +answer is a vector, and promotePoints has been set to 1, then the checker +will be called when the student answer is a vector OR a point. =item S 0 or 1 >>> -If 1 (the default), only call the -custom checker if the student answer -has the same number of coordinates as -the correct answer. +If 1 (the default), only call the custom checker if the student answer +has the same number of coordinates as the correct answer. =back @@ -107,10 +106,9 @@ sub custom_cmp { ); } -# # Set this to include any default parameters you want # to include in the custom answer checkers -# + @custom_cmp_defaults = (); =head2 custom_list_cmp @@ -170,9 +168,8 @@ sub custom_list_cmp { ); } -# # Set this to include any default parameters you want -# to include in the custom answer checkers -# +# to include in the custom answer checkers. + @custom_list_cmp_defaults = (); diff --git a/macros/answers/answerHints.pl b/macros/answers/answerHints.pl index 5eb37a25a0..86b0712901 100644 --- a/macros/answers/answerHints.pl +++ b/macros/answers/answerHints.pl @@ -1,14 +1,20 @@ -=head1 AnswerHints() +=head1 NAME -This is an answer-checker post-filter that allows you to produce +answerHints.pl - provides methods for answer hints + +=head1 DESCRIPTION + +This macro provides an answer-checker post-filter that allows you to produce additional error messages for incorrect answers. You can trigger a message for a single answer, a collection of answers, or via a subroutine that determines the condition for the message. -Note that this filter only works for MathObjects answer checkers. +=head1 MACROS + +=head2 AnswerHints() -The answer hints are given as a pair using => with the right-hand +The answer hints are given as a pair using C<< => >> with the right-hand side being the answer message and the left-hand side being one of three possibilities: 1) the value that triggers the message, 2) a reference to an array of values that trigger the message, or diff --git a/macros/answers/answerVariableList.pl b/macros/answers/answerVariableList.pl index 32b7ecc127..ecb9a0c81d 100644 --- a/macros/answers/answerVariableList.pl +++ b/macros/answers/answerVariableList.pl @@ -1,8 +1,11 @@ =head1 NAME -answerVariableList.pl - Creates answer checkers that compare the student's -answer to a list of variable names. +answerVariableList.pl - answer checker for list of variables + +=head1 DESCRIPTION + +Creates answer checkers that compare the student's answer to a list of variable names. =head1 MACROS @@ -78,7 +81,7 @@ sub variable_cmp { =head2 addVariables - addVariables(@vars) + addVariables(@vars) Adds each string in @vars as a varible to the current context. diff --git a/macros/answers/extraAnswerEvaluators.pl b/macros/answers/extraAnswerEvaluators.pl index 3da3987439..86ef9991fd 100644 --- a/macros/answers/extraAnswerEvaluators.pl +++ b/macros/answers/extraAnswerEvaluators.pl @@ -4,6 +4,11 @@ =head1 NAME extraAnswerEvaluators.pl - Answer evaluators for intervals, lists of numbers, and lists of points. +=head1 DESCRIPTION + +This is a list of macros that create "answer evaluators" for checking student +answers of various "exotic" types. + =head1 SYNPOSIS interval_cmp() -- checks answers which are unions of intervals. It can also @@ -22,10 +27,7 @@ =head1 SYNPOSIS instructor's equation. The student's equation must be of the same general type as the instructors to get credit. -=head1 DESCRIPTION -This file adds subroutines which create "answer evaluators" for checking student -answers of various "exotic" types. =cut diff --git a/macros/answers/unorderedAnswer.pl b/macros/answers/unorderedAnswer.pl index 548c26cd60..c63d02d378 100644 --- a/macros/answers/unorderedAnswer.pl +++ b/macros/answers/unorderedAnswer.pl @@ -1,7 +1,7 @@ =head1 NAME -unorderedAnswer.pl - allow the answers to be checked independent of order. +unorderedAnswer.pl - allow the answers to be checked independent of order =head1 SYNOPSIS @@ -19,6 +19,8 @@ =head1 DESCRIPTION sub _unorderedAnswer_init { }; # don't reload this file +=head1 MACROS + =head2 UNORDERED_ANS Collect a group of answer checkers for use with answers that can be given diff --git a/macros/contexts/contextABCD.pl b/macros/contexts/contextABCD.pl index 8ea56d687a..2d29d56170 100644 --- a/macros/contexts/contextABCD.pl +++ b/macros/contexts/contextABCD.pl @@ -1,4 +1,6 @@ +# Note: this should be deprecated. + =head1 NAME contextABCD.pl - Contexts for matching problems. @@ -9,6 +11,8 @@ =head1 DESCRIPTION for matching problems (where you match against A, B, C, D, and so on). +=head1 SYNOPSIS + There are two contexts defined here, Context("ABCD"); diff --git a/macros/contexts/contextAlternateDecimal.pl b/macros/contexts/contextAlternateDecimal.pl index ef9c3360f5..cccbb5efcd 100644 --- a/macros/contexts/contextAlternateDecimal.pl +++ b/macros/contexts/contextAlternateDecimal.pl @@ -1,9 +1,7 @@ =head1 NAME -C - Provides a context that allows the -entry of decimal numbers using a comma for the decimal indicator -rather than a dot (e.g., C<3,14159> rather than C<3.14159>). +contextAlternateDecimal.pl - allow the entry of decimal numbers with other decimal character =head1 DESCRIPTION @@ -13,11 +11,7 @@ =head1 DESCRIPTION the other form produces an error message when used. You can also force the display of numbers to use one or the other form. -=head1 USAGE - -To use this file, first load it into your problem, then select the -context that you wish to use. There are three pre-defined contexts, -C, C, and +There are three pre-defined contexts, C, C, and C. The first allows both the standard and alternate forms to be used, the second allows only the alternate form, and the third allows only the standard form, but recognizes the @@ -82,7 +76,7 @@ =head1 USAGE numebrs would be displayed in standard form. -=head1 LISTS IN ALTERNATE FORMAT +=head3 LISTS IN ALTERNATE FORMAT Because the alternate format allows numbers to be entered using commas rather than periods, this makes the formation of lists harder. For @@ -107,7 +101,7 @@ =head1 LISTS IN ALTERNATE FORMAT must be a list separator. -=head1 SETTING THE ALTERNATE FORM AS THE DEFAULT +=head3 SETTING THE ALTERNATE FORM AS THE DEFAULT If you want to force existing problems to allow (or force, or warn about) the alternate format instead, then create a file named diff --git a/macros/contexts/contextAlternateIntervals.pl b/macros/contexts/contextAlternateIntervals.pl index 40ac14a284..6ea0579721 100644 --- a/macros/contexts/contextAlternateIntervals.pl +++ b/macros/contexts/contextAlternateIntervals.pl @@ -1,10 +1,8 @@ =head1 NAME -C - Provides a context that allows the -entry of intervals using reversed bracket notation for open endpoints -(e.g., C<]a,b[> rather than C<(a,b)> for an open interval). - +contextAlternateIntervals - Provides a context that allows the +entry of intervals using reversed bracket notation =head1 DESCRIPTION @@ -14,9 +12,6 @@ =head1 DESCRIPTION form produces an error message when used. You can also force the display of intervals to use one or the other form. - -=head1 USAGE - To use this file, first load it into your problem, then select the context that you wish to use. There are three pre-defined contexts, C, C, and @@ -83,7 +78,7 @@ =head1 USAGE would allow students to enter intervals in either format, but all intervals would be displayed in standard form. -=head1 Setting the alternate form as the default +=head3 Setting the alternate form as the default If you want to force existing problems that use the Interval context to use one of the alternate contexts instead, then create a file named @@ -122,14 +117,10 @@ =head1 Setting the alternate form as the default =cut -########################################################################## - loadMacros("MathObjects.pl"); sub _contextAlternateIntervals_init { context::AlternateIntervals->Init } -########################################################################## - package context::AlternateIntervals; # Create the AlternateIntervals contexts @@ -176,23 +167,22 @@ sub Enable { $context->lists->set("Interval" => { class => "context::AlternateIntervals::Parser::Interval" }); } -# # Sets the default Interval context to use alternate decimals. The # two arguments determine the values for the enterIntervals and # displayIntervals flags. If enterIntervals is "alternate", then # student answers must use the alternate format for entering # intervals (though professors can use either). -# + sub Default { my $self = shift; my $enter = shift || "either"; my $display = shift || "either"; my $cmp = ($enter eq "alternate"); $enter = "either" if $cmp; - # + # This adds the names from InequalitySetBuilder, but we need a better way to # link into contexts as they are created and copied. - # + my @InequalitySetBuilder = ( "SetBuilder::", "InequalitySetBuilder::", "InequalitySetBuilderInterval::", "InequalitySetBuilderUnion::", @@ -211,8 +201,6 @@ sub Default { main::Context(main::Context()->{name}); } -########################################################################## - package context::AlternateIntervals::Formula; our @ISA = ('Value::Formula'); @@ -245,13 +233,12 @@ sub Open { $self->push($item); } -# # We need to modify the test for formInterval to NOT check the number # of entries so that better error messages are produced, and to handle # multiple close delimiters. These are both in teh "operand" branch, # so do the original for all the choices, and copy that branch here, # with our modifications. -# + sub Close { my ($self, $type, $ref) = @_; $self->{ref} = $ref; @@ -306,8 +293,6 @@ sub Close { sub class {'Formula'} -########################################################################## - package context::AlternateIntervals::Interval; our @ISA = ('Value::Interval'); diff --git a/macros/contexts/contextArbitraryString.pl b/macros/contexts/contextArbitraryString.pl index 55cdbc56b6..3b20f60dbb 100644 --- a/macros/contexts/contextArbitraryString.pl +++ b/macros/contexts/contextArbitraryString.pl @@ -4,12 +4,7 @@ =head1 NAME contextArbitraryString.pl - Implements a context in which the student's answer is treated as a literal string, and not parsed further. -=head1 DESCRIPTION - -Implements a context in which the student's answer is treated as a -literal string, and not parsed further. The real answer checking -should be performed in a custom checker passed to the answer -string's C method. E.g., +=head1 SYNOPSIS loadMacros("contextArbitraryString.pl"); Context("ArbitraryString"); @@ -26,6 +21,13 @@ =head1 DESCRIPTION return $score; })); +=head1 DESCRIPTION + +Implements a context in which the student's answer is treated as a +literal string, and not parsed further. The real answer checking +should be performed in a custom checker passed to the answer +string's C method. + The default checker is essentially that given above, so if you want the student answer to match the correct one exactly (spacing and case are significant), then you don't have to use a custom checker. @@ -79,16 +81,14 @@ sub _contextArbitraryString_init { $context->update; } -# # Handle creating String() constants -# + package context::ArbitraryString; sub new { shift; main::Compute(@_) } -# # Replacement for Parser::String that uses the original string verbatim # (but replaces \r and \r\n by \n to handle different browser multiline input) -# + package context::ArbitraryString::Parser::String; our @ISA = ('Parser::String'); @@ -100,16 +100,14 @@ sub new { $self->SUPER::new($equation, $value, $ref); } -# # Replacement for Value::String that creates preview strings # that work for multiline input -# + package context::ArbitraryString::Value::String; our @ISA = ("Value::String"); -# # Mark a multi-line string to be displayed verbatim in TeX -# + sub quoteTeX { my $self = shift; my $s = shift; @@ -119,9 +117,8 @@ sub quoteTeX { "\\begin{array}{l}" . join("\\\\ ", @tex) . "\\end{array}"; } -# # Quote HTML special characters -# + sub quoteHTML { my $self = shift; my $s = $self->SUPER::quoteHTML(shift); @@ -130,10 +127,8 @@ sub quoteHTML { return $s; } -# -# Adjust preview and strings so they display -# multiline answers properly. -# +# Adjust preview and strings so they display multiline answers properly. + sub cmp_preprocess { my $self = shift; my $ans = shift; diff --git a/macros/contexts/contextBaseN.pl b/macros/contexts/contextBaseN.pl index 94b3402c6a..805c171398 100644 --- a/macros/contexts/contextBaseN.pl +++ b/macros/contexts/contextBaseN.pl @@ -10,11 +10,9 @@ =head1 DESCRIPTION greater than or equal to 2. The numbers will be stored internally in decimal, though parsed and shown in the chosen base. -In addition, basic integer arithemetic (+,-,*,/,%,^) are available for these numbers. -Division is defined in an integer sense. - The original purpose for this is simple conversion and operations in another base, however -it is not limited to this. +it is not limited to this. In addition, basic integer arithemetic (+,-,*,/,%,^) are available for these numbers. +Division is defined in an integer sense. To use a non-decimal base MathObject, first load the contextBaseN.pl file: @@ -75,7 +73,7 @@ =head1 DESCRIPTION The last two digits for C are nonstandard. We want to avoid '+' and '/' here as they have arithmetic meaning. -=head2 Sample PG problem +=head3 Sample PG problem A simple PG problem that asks a student to convert a number into base-5: @@ -114,6 +112,8 @@ sub Init { $context->parens->undefine('|', '{', '['); } +=head1 MACROS + =head2 convertBase The function C converts the value from or to other bases depending on the options @@ -302,9 +302,8 @@ sub eval { package context::BaseN::BOP::modulo; our @ISA = ('Parser::BOP::divide'); -# # Do the division. -# + sub _eval { $_[1] % $_[2] } # A replacement for Value::Real that handles non-decimal integers diff --git a/macros/contexts/contextBoolean.pl b/macros/contexts/contextBoolean.pl index a3bdcf7e65..5369d54e1b 100644 --- a/macros/contexts/contextBoolean.pl +++ b/macros/contexts/contextBoolean.pl @@ -5,6 +5,10 @@ =head1 NAME =head1 DESCRIPTION +This macro provides functionality to handle boolean expression + +=head1 SYNOPSIS + Load this file: loadMacros('contextBoolean.pl'); @@ -13,7 +17,7 @@ =head1 DESCRIPTION Context('Boolean'); -=head2 CONSTANTS +=head3 CONSTANTS This constant recognizes two constants by default, C and C. The following are all equivalent: @@ -22,14 +26,14 @@ =head2 CONSTANTS $T = Context()->T; $T = context::Boolean->T; -=head2 VARIABLES +=head3 VARIABLES By default, this context has two variables, C

and C. More variables can be added through the usual means of modifying context: Context->variables->add( r => 'Boolean' ); -=head2 OPERATORS +=head3 OPERATORS Changing the LaTeX representations of the boolean operators is handled through the operators C, C, C, and C. Note the extra space following the LaTeX command. @@ -66,7 +70,7 @@ =head3 Aliases and Alternatives =back -=head2 OPERATOR PRECEDENCE +=head3 OPERATOR PRECEDENCE =over @@ -86,7 +90,7 @@ =head2 OPERATOR PRECEDENCE =back -=head2 REDUCTION +=head3 REDUCTION The context also handles C with the following reduction rules: @@ -114,7 +118,7 @@ =head2 REDUCTION =back -=head2 COMPARISON +=head3 COMPARISON Boolean Formula objects are considered equal whenever the two expressions generate the same truth table. diff --git a/macros/contexts/contextComplexExtras.pl b/macros/contexts/contextComplexExtras.pl index 2f91b70771..a17d229810 100644 --- a/macros/contexts/contextComplexExtras.pl +++ b/macros/contexts/contextComplexExtras.pl @@ -1,7 +1,7 @@ =head1 NAME -F - Add conjugation to Complex contexts, and +contextCopmlesExtras.pl - Add conjugation to Complex contexts, and transpose, conjugate transpose, trace, and determinant to Complex-Matrix context. =head1 DESCRIPTION @@ -11,6 +11,8 @@ =head1 DESCRIPTION answers in the Complex-Matrix context, and adds conjugation to all Complex contexts. +=head1 SYNOPSIS + Conjugation is represented by C<~>, as in C<~z> or C<~M> to conjugate a complex number or complex matrix. This can be used in both PG code as well as student answers. The transpose is represented by C<^T>, as @@ -95,27 +97,22 @@ sub _contextComplexExtras_init { ); } -#################################################### -# # Base UOP class that checks for matrix arguments -# + package context::ComplexExtras::UOP; our @ISA = ("Parser::UOP"); -# # Check that the operand is a Matrix -# + sub _check { my $self = shift; $self->Error("'%s' is only defined for Matrices", $self->{def}{string}) unless $self->{op}->type eq "Matrix"; } -#################################################### -# # Implements the ~ operation on matrices and complex numbers # (as a left-associative unary operator) -# + package context::ComplexExtras::UOP::conjugate; our @ISA = ("context::ComplexExtras::UOP"); @@ -127,11 +124,9 @@ sub _check { sub _eval { shift; $_[0]->conj } -#################################################### -# # Implements the ^T operation on matrices and complex numbers # (as a right-associative unary operator) -# + package context::ComplexExtras::UOP::transpose; our @ISA = ("context::ComplexExtras::UOP"); @@ -142,11 +137,9 @@ sub perl { return '(' . $self->{op}->perl . '->transpose)'; } -#################################################### -# # Implements the ^* operation on matrices and complex numbers # (as a right-associative unary operator) -# + package context::ComplexExtras::UOP::conjtrans; our @ISA = ("context::ComplexExtras::UOP"); @@ -157,34 +150,27 @@ sub perl { return '(' . $self->{op}->perl . '->transpose->conj)'; } -#################################################### -# # Implement functions with one matrix input and complex output -# + package context::ComplexExtras::Function::matrix; our @ISA = ("Parser::Function"); -# # Check for a single Matrix-valued input -# + sub _check { (shift)->checkMatrix("complex") } -# # Evaluate by promoting to a Matrix # and then calling the routine from the Value package -# + sub _eval { my $self = shift; my $name = $self->{def}{method} || $self->{name}; $self->Package("Matrix")->promote($self->context, $_[0])->$name; } -# -# Check for a single Matrix-valued argument -# Then promote it to a Matrix (does error checking) -# and call the routine from Value package (after -# converting "tr" to "trace") -# +# Check for a single Matrix-valued argument. Then promote it to a Matrix (does error checking) +# and call the routine from Value package (after converting "tr" to "trace") + sub _call { my $self = shift; my $name = shift; @@ -195,3 +181,5 @@ sub _call { $name = "trace" if $name eq "tr"; # method of Matrix is trace not tr $self->Package("Matrix")->promote($context, $M)->$name; } + +1; diff --git a/macros/contexts/contextComplexJ.pl b/macros/contexts/contextComplexJ.pl index 897ef8ac8f..82926fa8a4 100644 --- a/macros/contexts/contextComplexJ.pl +++ b/macros/contexts/contextComplexJ.pl @@ -1,7 +1,7 @@ =head1 NAME -C - Alters the Complex context to allow the +contextComplexJ.pl - Alters the Complex context to allow the use of j-notation in addition to (or in place of) i-notation for complex numbers. @@ -14,9 +14,6 @@ =head1 DESCRIPTION type), and how complex numbers should be displayed (you can force either form to be used regardless of how they were entered). - -=head1 USAGE - To use this file, first load it into your problem, then use the Complex context as usual. Both i and j notation will be allowed, and numbers will display in whichever format they were originally @@ -68,7 +65,7 @@ =head1 USAGE all numebrs would be displayed in standard form. -=head1 SETTING THE ALTERNATE FORM AS THE DEFAULT +=head3 SETTING THE ALTERNATE FORM AS THE DEFAULT If you want to force existing problems to allow (or force, or warn about) the j notation, then create a file named @@ -106,8 +103,6 @@ =head1 SETTING THE ALTERNATE FORM AS THE DEFAULT =cut -########################################################################## - loadMacros("MathObjects.pl"); sub _contextComplexJ_init { @@ -115,13 +110,10 @@ sub _contextComplexJ_init { context::ComplexJ->Enable($context); } -############################################################### - package context::ComplexJ; -# # Enables complex j notation in the given context -# + sub Enable { my $self = shift; my $context = shift || main::Context(); @@ -144,13 +136,12 @@ sub Enable { $context->update; } -# # Sets all the complex-based default contexts to use ComplexJ # notation. The two arguments determine the values for the # enterComplex and displayComplex flags. If enterComplex is "j", # then student answers must use the j notation (though # professors can use either). -# + sub Default { my $self = shift; my $enter = shift || "either"; @@ -171,11 +162,7 @@ sub Default { main::Context(main::Context()->{name}); } -############################################################### -# -# Handle Complex numbers so that they are displayed -# with the proper i or j value. -# +# Handle Complex numbers so that they are displayed with the proper i or j value. package context::ComplexJ::Value::Complex; our @ISA = ('Value::Complex'); @@ -196,11 +183,7 @@ sub TeX { return $z; } -############################################################### -# -# Make Parser Value object maintain the indicator for -# which notation was used for a complex number. -# +# Make Parser Value object maintain the indicator for which notation was used for a complex number. package context::ComplexJ::Parser::Value; our @ISA = ('Parser::Value'); @@ -218,11 +201,7 @@ sub new { sub class {'Value'} -############################################################### -# -# Make sure complex numbers maintain their flag for -# which format was used to create them. -# +# Make sure complex numbers maintain their flag for which format was used to create them. package context::ComplexJ::Parser::Complex; our @ISA = ('Parser::Complex'); @@ -236,14 +215,9 @@ sub eval { sub class {'Complex'} -############################################################### -# -# Produce error messages when the wrong notation -# is used for complex numbers. -# -# Swap i and j when required by the displayComplex flag -# in the output of constants. -# +# Produce error messages when the wrong notation is used for complex numbers. + +# Swap i and j when required by the displayComplex flag in the output of constants. package context::ComplexJ::Parser::Constant; our @ISA = ('Parser::Constant'); @@ -285,6 +259,4 @@ sub TeX { sub class {'Constant'} -############################################################### - 1; diff --git a/macros/contexts/contextCongruence.pl b/macros/contexts/contextCongruence.pl index 1e8df7a13b..8da673b2ca 100644 --- a/macros/contexts/contextCongruence.pl +++ b/macros/contexts/contextCongruence.pl @@ -1,10 +1,6 @@ -=encoding UTF-8 =head1 NAME - - -C - Provides contexts that allow the -entry of congruence solutions +contextCongruence.pl - Provides contexts that allow the entry of congruence solutions =head1 DESCRIPTION @@ -19,9 +15,6 @@ =head1 DESCRIPTION Congruences must be created with three paramters (a, b, m) from ax ≡ b (mod m). -=head1 USAGE - - loadMacros("contextCongruence.pl"); Context("Congruence"); @@ -71,14 +64,11 @@ =head1 USAGE sub _contextCongruence_init { context::Congruence::Init() } -########################################################################### - package context::Congruence; our @ISA = ('Value::Formula'); -# # Initialize the contexts and make the creator function. -# + sub Init { my $context = $main::context{Congruence} = Parser::Context->getCopy("Numeric"); $context->{name} = "Congruence"; @@ -99,9 +89,8 @@ sub Init { 0 # default display only general solution. switch to 1 to display all possible solutions ); - # # Only allow general solution for answer and output - # + $context = $main::context{"Congruence-General-Solution"} = $context->copy; $context->{name} = "Congruence-General-Solution"; $context->flags->set( @@ -110,9 +99,8 @@ sub Init { outputAllSolutions => 0 ); - # # Only allow all solutions for answer and output - # + $context = $main::context{"Congruence-All-Solutions"} = $context->copy; $context->{name} = "Congruence-All-Solutions"; $context->flags->set( @@ -194,9 +182,8 @@ sub allSolutions { return Value::Formula->new($self->context, join(",", @solutions)); } -# # Produce a string version -# + sub string { my $self = shift; my $outputAllSolutions = $self->getFlag("outputAllSolutions"); @@ -208,9 +195,8 @@ sub string { } } -# # Produce a TeX version -# + sub TeX { my $self = shift; my $outputAllSolutions = $self->getFlag("outputAllSolutions"); @@ -231,9 +217,8 @@ sub typeMatch { package context::Congruence::Function::Numeric3; # checks for 3 numeric inputs our @ISA = qw(Parser::Function); -# # Check for two real-valued arguments -# + sub _check { my $self = shift; return if ($self->checkArgCount(3)); @@ -255,9 +240,8 @@ sub _check { } } -# # Check that the inputs are OK -# + sub _call { my $self = shift; my $name = shift; @@ -268,20 +252,19 @@ sub _call { return $self->$name(@_); } -# # Call the appropriate routine -# + sub _eval { my $self = shift; my $name = $self->{name}; $self->$name(@_); } -# # Congruence Class # ax ≡ b (mod m) # # returns gcd, residue, divisor + sub _getCongruenceData { my $a = shift; my $b = shift; diff --git a/macros/contexts/contextCurrency.pl b/macros/contexts/contextCurrency.pl index 2973c7cc5f..dc7da28a9c 100644 --- a/macros/contexts/contextCurrency.pl +++ b/macros/contexts/contextCurrency.pl @@ -153,16 +153,13 @@ =head1 DESCRIPTION =cut loadMacros("MathObjects.pl"); -#loadMacros("problemPreserveAnswers.pl"); # obsolete sub _contextCurrency_init { Currency::Init() } package Currency; -# -# Initialization creates a Currency context object -# and sets up a Currency() constructor. -# +# Initialization creates a Currency context object and sets up a Currency() constructor. + sub Init { my $context = $main::context{Currency} = new Currency::Context(); $context->{name} = "Currency"; @@ -170,20 +167,17 @@ sub Init { main::PG_restricted_eval('sub Currency {Value->Package("Currency")->new(@_)}'); } -# # Quote characters that are special in regular expressions -# + sub quoteRE { my $s = shift; $s =~ s/([-\\^\$+*?.\[\](){}])/\\$1/g; return $s; } -# -# Quote common TeX special characters, and put -# the result in {\rm ... } if there are alphabetic +# Quote common TeX special characters, and put the result in {\rm ... } if there are alphabetic # characters included. -# + sub quoteTeX { my $s = shift; my $isText = ($s =~ m/[a-z]/i); @@ -196,21 +190,14 @@ sub quoteTeX { return $s; } -###################################################################### -###################################################################### +# The Currency context has an extra "currency" data type (like flags, variables, etc.) # -# The Currency context has an extra "currency" data -# type (like flags, variables, etc.) -# -# It also creates some patterns needed for handling -# currency values, and sets the Parser and Value +# It also creates some patterns needed for handling currency values, and sets the Parser and Value # hashes to activate the Currency objects. # -# The tolerance is set to .005 absolute so that -# answers must be correct to the penny. You can -# change this in the context, or for individual -# currency values. -# +# The tolerance is set to .005 absolute so that answers must be correct to the penny. You can +# change this in the context, or for individual currency values. + package Currency::Context; our @ISA = ('Parser::Context'); @@ -262,12 +249,8 @@ sub new { sub currency { (shift)->{_currency} } # access to currency data -################################################## -# -# This is the context data for currency. -# A special pattern is maintained for the -# comma form of numbers (using the specified -# comma and decimal-place characters). +# This is the context data for currency. A special pattern is maintained for the +# comma form of numbers (using the specified comma and decimal-place characters). # # You specify the currency symbol via # @@ -312,9 +295,8 @@ sub init { sub addToken { } # no tokens are needed (only uses fixed pattern) sub removeToken { } -# # Create, set and remove extra currency symbols -# + sub addSymbol { my $self = shift; my $operators = $self->{context}->operators; @@ -335,11 +317,10 @@ sub addSymbol { sub setSymbol { (shift)->{context}->operators->set(@_) } sub removeSymbol { (shift)->{context}->operators->remove(@_) } -# # Update the currency patterns in case the characters have changed, # and if the symbol has changed, remove the old operator(s) and # create a new one for the given symbol. -# + sub update { my $self = shift; my $context = $self->{context}; @@ -378,13 +359,10 @@ sub symbolString { return $associativity eq 'left' ? "$symbol " : " $symbol"; } -###################################################################### -###################################################################### -# # When creating Number objects in the Parser, we need to remove the # comma (and currency) characters and replace the decimal character # with an actual decimal point. -# + package Currency::Number; our @ISA = ('Parser::Number'); @@ -401,10 +379,10 @@ sub new { $value =~ s/$pattern->{currencyChars}//g; # get rid of currency characters $value =~ s/$pattern->{currencyDecimal}/./; # convert decimal to . } elsif (Value::classMatch($value, "Currency")) { - # + # Put it back into a Value object, but must unmark it # as a Real temporarily to avoid an infinite loop. - # + $value->{isReal} = 0; $value = $self->Item("Value")->new($equation, [$value]); $value->{value}{isReal} = 1; @@ -415,13 +393,9 @@ sub new { return $self; } -################################################## -# -# This class implements the currency symbol. -# It checks that its operand is a numeric constant -# in the correct format, and produces -# a Currency object when evaluated. -# +# This class implements the currency symbol. It checks that its operand is a numeric constant +# in the correct format, and produces a Currency object when evaluated. + package Currency::UOP::currency; our @ISA = ('Parser::UOP'); @@ -446,30 +420,23 @@ sub _check { sub _eval { my $self = shift; Value->Package("Currency")->make($self->context, @_) } -# # Use the Currency MathObject to produce the output formats -# + sub string { (shift)->eval->string } sub TeX { (shift)->eval->TeX } sub perl { (shift)->eval->perl } -###################################################################### -###################################################################### -# # This is the MathObject class for currency objects. # It is basically a Real(), but one that stringifies # and texifies itself to include the currency symbol # and commas every three digits. -# + package Currency::Currency; our @ISA = ('Value::Real'); -# -# We need to override the new() and make() methods -# so that the Currency object will be counted as -# a Value object. If we aren't promoting Reals, -# produce an error message. -# +# We need to override the new() and make() methods so that the Currency object will be counted as +# a Value object. If we aren't promoting Reals, produce an error message. + sub new { my $self = shift; my $class = ref($self) || $self; @@ -504,13 +471,12 @@ sub truncate { return $self->make($n + 0); } -# # Look up the currency symbols either from the object of the context # and format the output as a currency value (use 2 decimals and # insert commas every three digits). Put the currency symbol # on the correct end for the associativity and remove leading # and trailing spaces. -# + sub format { my $self = shift; my $type = shift; @@ -546,14 +512,12 @@ sub stringify { sub string { (shift)->format("string") } sub TeX { (shift)->format("TeX") } -# # Override the class name to get better error messages -# + sub cmp_class {"a Monetary Value"} -# # Add promoteReals option to allow Reals with no dollars -# + sub cmp_defaults { ((shift)->SUPER::cmp_defaults, promoteReals => 0,) } sub typeMatch { @@ -564,6 +528,4 @@ sub typeMatch { return Value::classMatch($other, 'Currency'); } -###################################################################### - 1; diff --git a/macros/contexts/contextExtensions.pl b/macros/contexts/contextExtensions.pl index c9f8700dbe..a1f077a9ca 100644 --- a/macros/contexts/contextExtensions.pl +++ b/macros/contexts/contextExtensions.pl @@ -48,10 +48,6 @@ =head1 DESCRIPTION sub _contextExtensions_init { } -################################################################################################# -################################################################################################# - -# # This package provides create() and extend() functions that can be # used to get a copy of an existing context and extend it by # overriding the existing classes with your own, while maintaining @@ -59,24 +55,22 @@ =head1 DESCRIPTION # on them for any situations that don't involve your new # functionality. These functions are designed so that multiple # extensions can be added without interfering with one another. -# + package context::Extensions; -# # ID to use for contexts that need a dynamic extension -# + my $id = 0; -# # Copy the given context (given by name or as a Context object) # and name the new one. For example, -# + # $context = context::Extensions::create("Quaternions", "Complex"); -# + # would create a context named "Quaternions-Complex" as a copy of the # Complex context. The implementation for classes added to this # context should be in the context::Quaternions namespace. -# + sub create { my ($new, $from) = @_; my $name = "$new-$from"; @@ -87,21 +81,20 @@ sub create { return $context; } -# # Extend a given Context object to include new features by specifying # classes to use for operators, functions, value object, and parser # objects, while retaining the old classes for fallback use. -# + # The changes are specified in the options following the Context, and these # can include: -# + # opClasses => { op => 'class', ... } -# + # specifies the operators to override, and the class suffix to # use for their implementations. For example, using -# + # opClasses => { '+' => 'BOP::add' } -# + # would attach the class context::Quaternions::BOP::add to the # plus sign in our Quaternion setting. If the space operator (' ') # is in your list, and if the original context has it point to an @@ -109,30 +102,30 @@ sub create { # is redirected automatically to 'BOP::Space' in your base context # package. In our case, we would want to include a definition for # context::Quaternions::BOP::Space in order to cover that possibility. -# + # ops => { op => {def}, ... } -# + # specifies new operators to add to the context (where "def" is # an operator definition like those for any context). -# + # functions => 'class1|class2|...' -# + # specifies the function categories that you are overriding (e.g., -# + # functions => 'numeric|trig|hyperbolic' -# + # would override the functions that have classes that end in # ::Functions:numeric, ::Function::trig, or ::Function::hyperbolic # and direct them to your own versions of these. In our quaternion # setting that would be to context::Quaternions::Function::numeric # for the first of these, and similarly for the others. -# + # value => ['Class1', 'Class2', ...] -# + # specifies the Value object classes to override. For instance, -# + # value => ['Real', 'Formula'] -# + # would set $context->{value}{Real} and $context->{value}{Formula} # to point to your own versions of these (e.g., in our example, # these would be context::Quaternions::Value::Real and @@ -140,52 +133,52 @@ sub create { # the parenthesized version (used by the corresponding constructor # functions), then the parentheses are replaced by "_Parens" in the # class name. For example, -# + # value => ['Real()'] -# + # would set -# + # $context->{value}{Real()} = 'context::Quaternions::Value::Real_Parens'; -# + # parser => ['Class1', 'Class2', ... ] -# + # specifies the Parser classes to override. This works similarly # to the "value" option above, so that -# + # parser => ['Number'] -# + # would set $context->{parser}{Number} to your version of this class, # which would be context::Quaternions::Parser::Number in our example. -# + # flags => { flag => value, ...} -# + # specifies the new flags to add to the context (or existing ones to # override. -# + # reductions => { name => 1 or 0, ... } -# + # specifies new reduction rules to add to the context, and # whether they are in effect by default (1) or not (0). Of # course, you need to implement these reduction rules in your # Parser objects. -# + # context => "Context" -# + # specifies that your context is a subclass of Parser::Context # that adds methods to the context. If specified, the modified # context will be blessed using this value as the suffix for the # context's class. In our quaternion example, the value "Context" # would mean the resulting modified context would be blessed # as context::Quaternions::Context. -# + # The extend() function returns the modified context. -# + # The various operators, functions, and value and Parser objects that # you define should use the context::Extensions::Super package below # in order to access the original classes for those objects. Ideally, # your new objects will mutate (i.e., re-bless) themselves to their # original classes if they don't involve your new MathObjects. -# + # For example, the new context::Quaternions::BOP::add class should # have the context::Extensions::Super object as one of its # superclasses, and then its _check() method could check if either @@ -194,26 +187,23 @@ sub create { # class and perform its _check() actions. That way, the new BOP::add # class only needs to worry about implementing the situation for # quaternions, and lets the original class deal with everything else. -# + sub extend { my ($context, %options) = @_; - # # The main context package - # + my $class = "context::$context->{baseName}"; - # # Extension data are stored in a context property - # + $context->{$class} = {}; push(@{ $context->{data}{values} }, $class); my $data = $context->{$class}; - # # Replace existing classes, but save the originals in the # class data for the context - # + my $operators = $context->operators; my $opClass = $options{opClasses} || {}; for my $op (keys %$opClass) { @@ -221,16 +211,15 @@ sub extend { makeOpSubclass($context, $data, $operators, $def->{string}, 'BOP::Space', 1) if $op eq ' ' && !$opClass->{ $def->{string} }; } - # + # Make any new operators that are needed - # + $operators->set(%{ $options{ops} }) if $options{ops}; - # # We tie into the existing function definitions in order to handle # arguments for this extension, but inherit the rest from the # original function classes. - # + if ($options{functions}) { my $functions = $context->functions; my $pattern = qr/::Function::(?:$options{functions})$/; @@ -254,26 +243,22 @@ sub extend { } } - # # Replace any Parser/Value classes that are needed, saving the # originals in the class data for the context - # + makeSubclass($context, $data, "Value", $_) for (@{ $options{value} || [] }); makeSubclass($context, $data, "Parser", $_) for (@{ $options{parser} || [] }); - # # Add any new flags requested - # + $context->flags->set(%{ $options{flags} }) if $options{flags}; - # # Add any new reduction options - # + $context->reduction->set(%{ $options{reductions} }) if $options{reductions}; - # # If there is a special context class, use it - # + if ($options{context}) { if (ref($context) ne 'Parser::Context') { $id++; @@ -283,16 +268,14 @@ sub extend { bless $context, "${class}::$options{context}"; } - # # Return the context - # + return $context; } -# # Record original operator class and set the new one, # extending to a new class if needed. -# + sub makeOpSubclass { my ($context, $data, $operators, $op, $class, $extend) = @_; my $def = $operators->get($op); @@ -302,9 +285,8 @@ sub makeOpSubclass { return $def; } -# # Record original class for a given Value or Parser class -# + sub makeSubclass { my ($context, $data, $Type, $Name) = @_; my $type = lc($Type); @@ -322,12 +304,8 @@ sub makeSubclass { } } -################################################################################################# -################################################################################################# - -# # A common class for getting the super-class of an extension class. -# + # This class handles all the details of dealing with the original # object classes that you have overridden in the context. You should # create a subclass of this class and define its extensionContext() @@ -336,28 +314,28 @@ sub makeSubclass { # original context's classes. (This is not strictly necessary, but # it is more efficient to do this than to have the Super class # have to figure it out every time a Super method is used.) -# + # For our quaternions example, you would use -# + # package context::Quaternions::Super # our @ISA = ('context::Extensions::Super'); -# + # sub extensionContext { 'context::Quaternions' } -# + # and then use 'context::Quaternions::Super' in the @ISA of your new # classes for operators, functions, or Value or Parser objects. # E.g., -# + # package context::Quaternions::BOP::add; # our @ISA = ('context::Quaternions::Super', 'Parser::BOP'); -# + # sub _check { # my $self = shift; # return $self->mutate->_check # unless $self->{lop}->class eq 'Quaternion' || $self->{rop}->class eq 'Quaternion'; # # Do your checking for proper arguments to go along with a quaternion here # } -# + # sub _eval { # # Do what is needed to perform addition between quaternions or between # # a quaternion or another legal value here. You don't have to worry @@ -365,39 +343,37 @@ sub makeSubclass { # # the class to the original class (and its _eval() method) if one # # of the operands isn't a quaternion. # } -# + # If you need to call a method from the original class, use -# + # &{$self->super("method")}($self, args...); -# + # where "method" is the name of the method to call, and "args" are any arguments # that you need to pass. For example, -# + # my $string = &{$self->super("string")}($self); -# + # would get the string output from the original class. -# + # If you are defining a new() or make() method (where the $self could be # the class name rather than a class instance), you will need to pass the # context to mutate(), super(), or superClass(). See the example for # new() below. -# + # The superClass() method gets you the name of the original class, in # case you need to access any class variables from that. -# + package context::Extensions::Super; -# # Get a method from the original class from the extended context -# + sub super { my ($self, $method, $context) = @_; return $self->superClass($context)->can($method); } -# # Get the super class name from the extension hash in the context -# + sub superClass { my $self = shift; my $class = ref($self) || $self; @@ -407,10 +383,9 @@ sub superClass { return $op ? $data->{$op} : $data->{ substr($class, length($name) + 2) }; } -# # Re-bless the current object to become the other object, # if there is one, or the object's super class if not. -# + sub mutate { my ($self, $context, $other) = @_; if ($other) { @@ -425,18 +400,16 @@ sub mutate { return $self; } -# # Use the super-class new() method -# + sub new { my $self = shift; my $context = Value::isContext($_[0]) ? $_[0] : $self->context; return &{ $self->super("new", $context) }($self, @_); } -# # Get the object's class from its class name -# + sub class { my $self = shift; my @class = split(/::/, ref($self) || $self); @@ -444,113 +417,105 @@ sub class { return $name eq 'Value' || $name eq 'Parser' ? $class[-1] : $name; } -# # This method assumes the extension is in a class named # "context::" where is replaced by the name of the # context. E.g., context::Quaternions in our example. -# + # That assumption can be changed by subclassing # context::Extensions::Super package and overriding this method with # one that returns the extension context's name. It is more efficient # to do that, anyway, but you can get away without it. -# + sub extensionContext { my $self = shift; my $class = join('::', (split(/::/, ref($self) || $self))[ 0, 1 ]); return $class; } -################################################################################################# -################################################################################################# - -# # A common class for handling the private extension data in an object's typeRef. -# + # This allows you to add and retrieve custom data to and from an # object's type in such a way that it doesn't interfere with the # original object's type, or that of any other extensions. -# + # A MathObject's typeRef property is a HASH that includes information # about the object's type, its length (for things like lists and # vectors), and entry types (again for objects like lists and # vectors). We can add data to this hash to store additional # information that we need in order to be more granular about the # type or class of a Parser object. -# + # To use this, create a subclass of context::Extensions::Data that # has an extensionID() method that returns a name to use as the hash # key to store your custom data (the default is to use the base # context name). Your subclass should also include your Super class # as a parent class. For example: -# + # package context::Quaternions::Data; # our @ISA = ('context::Quaternions::Super', 'context::Extensions:Data'); -# + # sub extensionID { 'quatData' } -# + # Then use this new subclass in the @ISA list for any class that needs access # to your custom data. -# + # The extensionData() method returns the complete hash of your custom # data, from which you can extract the value of the property you # need, or can set any properties that you want. E.g., -# + # $self->extensionData->{class}; -# + # could be used to obtain the custom "class" property of your data. -# + # The setExtensionType() method is used to set an object's # $self->{type} property (which holds the object's typeRef) to a # named type residing in your base context. For example: -# + # package context::Quaternions; # our $QUATERNION = Value::Type("Number, undef, undef, quatData => {class => "QUATERNION"}); -# + # package context::Quaternions::Super # our @ISA = ('context::Extensions::Super'); # sub extensionContext { 'context::Quaternions' } -# + # package context::Quaternions::Data; # our @ISA = ('context::Quaternions::Super', 'context::Extensions:Data'); # sub extensionID { 'quatData' } -# + # package context::Quaternions::BOP::add; # our @ISA = ('context::Quaternions::Data', 'Parser::BOP'); -# + # sub _check { # my $self = shift; # unless $self->{lop}->class eq 'Quaternion' || $self->{rop}->class eq 'Quaternion'; # # other type checking here # $self->setExtensionType("QUATERNION"); # Use the type in the $QUATERNION variable above # } -# + # Finally, the extensionDataMatch() method checks if the value of a # given property is one of a set of values. For example, if you have # a property called "class", then -# + # $self->extensionDataMatch($self->{lop}, "class", "QUATERNION", "COMPLEX"); -# + # would return 1 if the quatData->{class} was either "QUATERNION" or # "COMPLEX" in the $self->{lop}{type} hash, and 0 otherwise. -# + package context::Extensions::Data; -# # Get the object's extensionData -# + sub extensionData { (shift)->typeRef->{ $self->extensionID } } -# # Set the object's extensionData (and the rest of its type) -# + sub setExtensionType { my ($self, $type) = @_; $self->{type} = ${ $self->extensionContext . "::${type}" }; } -# # Check if an object's extension property matches one of the given values -# + sub extensionDataMatch { my ($self, $x, $prop, @values) = @_; my $value = $x->typeRef->{ $self->extensionID }{$prop}; @@ -562,12 +527,8 @@ sub extensionDataMatch { return 0; } -# # The extension context can subclass that is produce a better name -# -sub extensionID { (shift)->extensionContext } -################################################################################################# -################################################################################################# +sub extensionID { (shift)->extensionContext } 1; diff --git a/macros/contexts/contextFiniteSolutionSets.pl b/macros/contexts/contextFiniteSolutionSets.pl index 1eff32875e..94274181d0 100644 --- a/macros/contexts/contextFiniteSolutionSets.pl +++ b/macros/contexts/contextFiniteSolutionSets.pl @@ -6,7 +6,14 @@ =head1 NAME =head1 DESCRIPTION -After setting the context to "FiniteSolutionSets", make an answer like: +This provides some common input forms for a finite solution set. + +Load the macro and set the Context: + + loadMacros('contextFiniteSolutionSets.pl'); + Context('FiniteSolutionSets'); + +Then create answers such as: Formula("1,2") Formula("1/2,2/3,3/4") @@ -173,15 +180,14 @@ sub _contextFiniteSolutionSets_init { my @correctanswers = $ansHash->{correct_value}->value; my $m = scalar(@correctanswers); # number of correct answers - # # Loop though the student answers - ## + for ($i = 0; $i < $n; $i++) { my $ith = ($n == 1) ? '' : Value::List->NameForNumber($i + 1); my $p = $studentanswers[$i]; # i-th student answer - # - # Check that the student's answer is a number or assignment - # + + # Check that the student's answer is a number or assignment + if ($p->class ne "Formula" or $p->type ne "Number" and $p->type ne "Assignment") { push(@errors, "Your $ith answer is not a number or assignment"); $score--; @@ -194,13 +200,13 @@ sub _contextFiniteSolutionSets_init { next; } } - # + # For assignments, grab number - # + my $q = ($p->type eq "Assignment") ? Formula((split('=', $p))[1]) : $p; - # + # Check that the number isn't an unreduced fraction - # + $mycontext = Context(); Context("Fraction"); Context()->flags->set(reduceFractions => 0); @@ -212,9 +218,9 @@ sub _contextFiniteSolutionSets_init { unless (($qfrac->value)[1] != 1); } Context($mycontext); - # + # Check that the number hasn't been given before - # + for ($j = 0, $used = 0; $j < $i; $j++) { my $r = $studentanswers[$j]; if ($r->class eq "Formula" and $r->type eq "Number" and $r == $q) { @@ -234,11 +240,11 @@ sub _contextFiniteSolutionSets_init { } } } - # + # If not already used, compare to each of the correct answers # and increase the score if there is a match. If there is no # match, take note if the failure is because of form - # + if (!$used) { my $qcmp; for ($k = 0, $match = 0, $badform = 0; $k < $m; $k++) { @@ -260,16 +266,16 @@ sub _contextFiniteSolutionSets_init { } } } - # + # Check that there are the right number of answers - # + if (!$ansHash->{isPreview}) { push(@errors, "You need to provide more numbers") if $n < $m and $score == $n; push(@errors, "You have given too many answers") if $score > $m; } - # + # Express a preference for formatting - # + if ($studentFormula->type ne 'Set' and $m == $score and Context()->flags->get('preferSetNotation') == 1) { push(@errors, "The preferred notation for the solution set is${BR}\\(\\left\\{" @@ -280,16 +286,13 @@ sub _contextFiniteSolutionSets_init { }; } -########################### -# # Subclass the numeric functions -# + package finiteSolutionSets::Function::numeric; our @ISA = ('Parser::Function::numeric'); -# # Override sqrt() to return a special value times x when evaluated -# + sub sqrt { my $self = shift; my $x = shift; @@ -309,9 +312,9 @@ sub identity { package finiteSolutionSets::Function::numeric2; our @ISA = ('parser::Root::Function::numeric2'); -# + # Override root(n,) to return a special value times x when evaluated -# + sub root { my $self = shift; my ($n, $x) = @_; diff --git a/macros/contexts/contextForm.pl b/macros/contexts/contextForm.pl index a7c6ab887a..6d26f3cdf3 100644 --- a/macros/contexts/contextForm.pl +++ b/macros/contexts/contextForm.pl @@ -1,12 +1,15 @@ =head1 NAME -This context distinguishes between "forms" of an expression by using bizarro +contextForm.pl - This context distinguishes between "forms" of an expression by using bizarro arithmetic. -For example, the answer could be "(x+1)(x+2)". Bizarro arithmetic always has +=head1 DESCRIPTION + +This context distinguishes between "forms" of an expression by using bizarro +arithmetic. For example, the answer could be "(x+1)(x+2)". Bizarro arithmetic always has commutative and associative addidition and multiplication, so it would be OK -to anwer with "(2+x)(x+1)". +to answer with "(2+x)(x+1)". But this context initally only uses bizarro with multiplication and division. So "x^2+3x+2" will not evaluate to the same as "(x+1)(x+2)". @@ -24,9 +27,6 @@ =head1 NAME and division while activating bizarro addition and subtraction) and then "(x+1)^2" and "(x+1)(x+1)" would be equivalent, yet distinct from "x^2+2x+1". - -=head1 DESCRIPTION - =cut loadMacros("MathObjects.pl", "bizarroArithmetic.pl", "parserRoot.pl",); @@ -44,7 +44,9 @@ sub _contextForm_init { setSqrt => exp(1) / main::ln(2), setRoot => exp(2) / main::ln(3), wrongFormMessage => - 'Your answer is algebraically equivalent to the correct answer, but not in the expected form. Maybe it is not fully simplified. Maybe something is not completely factored or expanded. Maybe it is not in the expected form for some other reason.', + 'Your answer is algebraically equivalent to the correct answer, but not in the expected form. ' + . 'Maybe it is not fully simplified. Maybe something is not completely factored or expanded. ' + . 'Maybe it is not in the expected form for some other reason.', ); $context->noreduce('(-x)+y', '(-x)-y'); diff --git a/macros/contexts/contextFraction.pl b/macros/contexts/contextFraction.pl index af047f8687..0cc9c637e6 100644 --- a/macros/contexts/contextFraction.pl +++ b/macros/contexts/contextFraction.pl @@ -257,9 +257,6 @@ =head1 DESCRIPTION sub _contextFraction_init { context::Fraction::Init() } -################################################################################################# -################################################################################################# - package context::Fraction; our @ISA = ('Parser::Context'); @@ -268,39 +265,33 @@ package context::Fraction; our $FRACTION = Value::Type("Number", undef, undef, fracData => { class => "FRACTION" }); our $MIXED = Value::Type("Number", undef, undef, fracData => { class => "MIXED" }); -# # Extend a given context (by name or actual Context object) to include fractions # The options are the default values for the Fraction context flags -# + sub extending { my ($from, %options) = @_; - # # Get a copy of the original context - # + my $context = context::Extensions::create("Fraction", $from); - # # Add fractions into the number pattern - # + $context->{pattern}{signedNumber} = '(?:' . $context->{pattern}{signedNumber} . '|-?\d+\s*/\s*-?\d+)'; - # # Define fractions as being above Infinity - # + $context->{value}{Fraction} = "context::Fraction::Value::Fraction"; $context->{precedence}{Fraction} = $context->{precedence}{Infinity} + .5; - # # Set the mixedNum class to be the original multiplication - # + my $operators = $context->operators; my $mult = $operators->get('*'); $context->{'context::Fraction'}{mixedNum} = $mult->{class}; - # # Extend the context with the needed classes and properties - # + return context::Extensions::extend( $context, opClasses => { @@ -348,9 +339,8 @@ sub extending { ); } -# # Initialize the contexts and make the creator function. -# + sub Init { my $context = $main::context{Fraction} = context::Fraction::extending('Numeric'); @@ -377,15 +367,13 @@ sub Init { main::PG_restricted_eval('sub Fraction { Value->Package("Fraction()")->new(@_)} ;'); } -# # Backward compatibility -# + sub contFrac { context::Fraction::Context->continuedFraction(@_) } sub toFraction { context::Fraction::Context->toFraction(@_) } -# # Greatest Common Divisor -# + sub gcd { my ($a, $b) = (abs(shift), abs(shift)); ($a, $b) = ($b, $a) if $a < $b; @@ -398,17 +386,15 @@ sub gcd { return $b; } -# # Least Common Multiple -# + sub lcm { my ($a, $b) = @_; return ($a / gcd($a, $b)) * $b; } -# # Reduced fraction -# + sub reduce { my ($a, $b) = @_; ($a, $b) = (-$a, -$b) if $b < 0; @@ -416,53 +402,48 @@ sub reduce { return ($a / $gcd, $b / $gcd); } -################################################################################################# -################################################################################################# - package context::Fraction::Context; our @ISA = ('Parser::Context'); sub class {'Context'} -# # Takes a positive real input and outputs an array (a,b) where a/b # is a very good fraction approximation with b no larger than # maxdenominator. -# + sub continuedFraction { my ($self, $x) = @_; my $step = $x; my $n = int($step); my ($h0, $h1, $k0, $k1) = (1, $n, 0, 1); my $maxdenominator = $_[2] || $self->flag('contFracMaxDen', 10**8); - # + # End when $step is an integer. - # + while ($step != $n) { $step = 1 / ($step - $n); - # + # Compute the next integer from the continued fraction sequence. - # + $n = int($step); - # + # Compute the next numerator and denominator according to the continued fraction formulas. - # + my ($newh, $newk) = ($n * $h1 + $h0, $n * $k1 + $k0); - # + # Machine rounding error may begin to make denominators skyrocket out of control - # + last if $newk > $maxdenominator; ($h0, $h1, $k0, $k1) = ($h1, $newh, $k1, $newk); } return ($h1, $k1); } -# # Convert a real to a reduced fraction approximation. -# + # Uses $context->continuedFracation() to convert .333333... into 1/3 # rather than 333333/1000000, etc. -# + sub toFraction { my ($self, $x, $max) = @_; my ($a, $b); @@ -477,23 +458,15 @@ sub toFraction { return [ $Real->make($a), $Real->make($b) ]; } -################################################################################################# -################################################################################################# - -# # A common class for getting the super-class of an extension class -# + package context::Fraction::Super; our @ISA = ('context::Extensions::Super'); sub extensionContext {'context::Fraction'} -################################################################################################# -################################################################################################# - -# # A common class for handling the fraction class data in an object's typeRef -# + package context::Fraction::Class; our @ISA = ('context::Fraction::Super', 'context::Extensions::Data'); @@ -502,16 +475,9 @@ package context::Fraction::Class; sub extensionClassMatch { (shift)->extensionDataMatch(shift, "class", @_) } sub setExtensionClass { (shift)->setExtensionType(@_) } -################################################################################################# -################################################################################################# - package context::Fraction::BOP::divide; our @ISA = ('context::Fraction::Class', 'Parser::BOP'); -# -# When strictFraction is in effect, only allow division -# with integers and negative integers -# sub _check { my $self = shift; my $lInt = $self->extensionClassMatch($self->{lop}, 'INTEGER', 'MINUS'); @@ -524,17 +490,15 @@ sub _check { if $self->context->flag("requireProperFractions") && CORE::abs($self->{lop}->eval) >= CORE::abs($self->{rop}->eval); } - # - # This is not a fraction, so convert to original class and - # do its _check - # + + # This is not a fraction, so convert to original class and do its _check + return $self->mutate->_check unless $lInt && $rInt; $self->setExtensionClass('FRACTION'); } -# # Create a Fraction from the given data -# + sub _eval { my $self = shift; my $context = $self->context; @@ -543,9 +507,8 @@ sub _eval { return $n; } -# # Reduce the fraction -# + sub reduce { my $self = shift; my $reduce = $self->{equation}{context}{reduction}; @@ -564,9 +527,8 @@ sub reduce { return $self; } -# # Display minus signs outside the fraction -# + sub TeX { my $self = shift; my $bop = $self->{def}; @@ -581,34 +543,29 @@ sub TeX { return $TeX; } -# # Derivative of fraction is 0 since it is constant -# + sub D { my $self = shift; return $self->Item('Number')->new($self->{equation}, 0); } -################################################################################################# -################################################################################################# - package context::Fraction::BOP::space; our @ISA = ('context::Fraction::Class', 'Parser::BOP'); -# # If the implied multiplication represents a proper fraction with a # preceding integer, then switch to the proper fraction operator # (for proper handling of string() and TeX() calls), otherwise, # convert the object to a standard multiplication. -# + sub _check { my $self = shift; my $context = $self->context; my $allowMixedNumbers = $context->flag("allowProperFractions") || $context->flag("allowMixedNumbers"); - # + # This is not a mixed number, so convert to original class and do # its _check - # + unless ($self->{bop} eq 'mixedNum' && $allowMixedNumbers && $self->extensionClassMatch($self->{lop}, 'INTEGER', 'MINUS') @@ -641,33 +598,26 @@ sub _check { } } -# # For when the space operator's string property sends to an # operator we didn't otherwise subclass. -# + package context::Fraction::BOP::Space; our @ISA = ('context::Fraction::BOP::space'); -################################################################################################# -################################################################################################# - -# # Implements the space between mixed numbers -# + package context::Fraction::BOP::and; our @ISA = ('Parser::BOP'); -# # For proper fractions, add the integer to the fraction -# + sub _eval { my ($self, $a, $b) = @_; return ($a >= 0 ? $a + $b : $a - $b)->with(showMixedNumbers => 1); } -# # Reduce the fraction -# + sub reduce { my $self = shift; my $reduce = $self->{equation}{context}{reduction}; @@ -685,23 +635,18 @@ sub reduce { return $self; } -# # Derivative of a mixed number is 0 since it is constant -# + sub D { my $self = shift; return $self->Item('Number')->new($self->{equation}, 0); } -################################################################################################# -################################################################################################# - package context::Fraction::UOP::minus; our @ISA = ('context::Fraction::Class', 'Parser::UOP'); -# # For strict fractions, only allow minus on certain operands -# + sub _check { my $self = shift; $self->{hadParens} = 1 if $self->{op}{hadParens}; @@ -714,9 +659,6 @@ sub _check { $self->mutate; } -################################################################################################# -################################################################################################# - package context::Fraction::Parser::Value; our @ISA = ('context::Fraction::Class', 'Parser::Value'); @@ -726,9 +668,8 @@ sub check { $self->mutate unless $self->{value}->classMatch('Fraction'); } -# # Handle reductions of negative fractions -# + sub reduce { my $self = shift; my $reduce = $self->context->{reduction}; @@ -738,9 +679,8 @@ sub reduce { return Parser::UOP::Neg($self); } -# # Add parentheses if they were there originally, or are needed by precedence -# + sub string { my $self = shift; my $string = &{ $self->super('string') }($self, @_); @@ -750,10 +690,9 @@ sub string { return $string; } -# # Add parentheses if they were there originally, or # are needed by precedence and we asked for exxxtra parens -# + sub TeX { my $self = shift; my $string = &{ $self->super('TeX') }($self, @_); @@ -765,17 +704,12 @@ sub TeX { return $string; } -# # Just return the fraction -# -sub makeMatrix { (shift)->{value} } -################################################################################################# -################################################################################################# +sub makeMatrix { (shift)->{value} } -# # Distinguish integers from decimals -# + package context::Fraction::Parser::Number; our @ISA = ('context::Fraction::Class', 'Parser::Number'); @@ -786,15 +720,11 @@ sub new { return $num->mutate; } -################################################################################################# -################################################################################################# - package context::Fraction::Value::Real; our @ISA = ('context::Fraction::Super', 'Value::Real'); -# # Allow Real to convert Fractions to Reals -# + sub new { my $self = shift; my $context = (Value::isContext($_[0]) ? shift : $self->context); @@ -804,10 +734,9 @@ sub new { return $self->mutate($context)->new($context, $x, @_); } -# # Since the signed number pattern now include fractions, we need to make sure # we handle them when a real is made and it looks like a fraction -# + sub make { my $self = shift; my $context = (Value::isContext($_[0]) ? shift : $self->context); @@ -817,21 +746,14 @@ sub make { return $self->mutate($context)->make($context, $x, @_); } -# # Since this is called directly, pass it up to the parent -# -sub cmp_defaults { (shift)->SUPER::cmp_defaults(@_) } -################################################## +sub cmp_defaults { (shift)->SUPER::cmp_defaults(@_) } package context::Fraction::Value::Real_Parens; our @ISA = ('context::Fraction::Value::Real'); -################################################################################################# -################################################################################################# -# # Implements the MathObject for fractions -# package context::Fraction::Value::Fraction; our @ISA = ('Value'); @@ -861,10 +783,9 @@ sub new { bless { data => [ $a, $b ], context => $context }, $class; } -# # Produce a real if one of the terms is not an integer # otherwise produce a fraction. -# + sub make { my $self = shift; my $class = ref($self) || $self; @@ -878,11 +799,10 @@ sub make { bless { data => [ $a, $b ], context => $context }, $class; } -# # Promote to a fraction, allowing reals to be $x/1 even when # not an integer (later $self->make() will produce a Real in # that case) -# + sub promote { my $self = shift; my $class = ref($self) || $self; @@ -897,9 +817,8 @@ sub promote { return $self->new($context, $x, @_); } -# # Create a new formula from the number -# + sub formula { my $self = shift; my $value = shift; @@ -909,41 +828,36 @@ sub formula { return $formula; } -# # Return the real number type -# + sub typeRef {$context::Fraction::FRACTION} sub length {2} sub isZero { (shift)->{data}[0] == 0 } sub isOne { (shift)->eval == 1 } -# # Return the real value -# + sub eval { my $self = shift; my ($a, $b) = $self->value; return $self->Package('Real')->new($self->context, $a / $b); } -# # Parts are not Value objects, so don't transfer -# + sub transferFlags { } -# # Check if a value is an integer -# + sub isInteger { my $n = shift; $n = $n->value if Value::isReal($n); return $n =~ m/^-?\d+$/; } -# # Get a flag that has been renamed -# + sub getFlagWithAlias { my $self = shift; my $flag = shift; @@ -951,10 +865,7 @@ sub getFlagWithAlias { return $self->getFlag($alias, $self->getFlag($flag)); } -################################################## -# # Binary operations -# sub add { my ($self, $l, $r, $other) = Value::checkOpOrderWithPromote(@_); @@ -1027,10 +938,7 @@ sub compare { $self->Error("You can't compare %s to %s", $self->showClass, $other->showClass); } -################################################## -# # Numeric functions -# sub abs { my $self = shift; $self->make(CORE::abs($self->{data}[0]), CORE::abs($self->{data}[1])) } sub neg { my $self = shift; $self->make(-($self->{data}[0]), $self->{data}[1]) } @@ -1038,10 +946,7 @@ sub compare { sub log { my $self = shift; $self->make(CORE::log($self->eval)) } sub sqrt { my $self = shift; $self->make(CORE::sqrt($self->{data}[0]), CORE::sqrt($self->{data}[1])) } -################################################## -# # Trig functions -# sub sin { my $self = shift; $self->make(CORE::sin($self->eval)) } sub cos { my $self = shift; $self->make(CORE::cos($self->eval)) } @@ -1051,20 +956,14 @@ sub atan2 { return $self->inherit($other)->make(CORE::atan2($l->eval, $r->eval)); } -################################################## -# # Differentiation -# sub D { my $self = shift; return $self->make(0, 1); } -################################################## -# # Utility -# sub reduce { my $self = shift; @@ -1081,10 +980,7 @@ sub isReduced { sub num { (shift->value)[0] } sub den { (shift->value)[1] } -################################################## -# # Formatting -# sub string { my ($self, $equation, $skip1, $skip2, $prec) = @_; @@ -1125,10 +1021,7 @@ sub pdot { return $n; } -########################################################################### -# # Answer Checker -# sub cmp_defaults { ( shift->SUPER::cmp_defaults(@_), @@ -1166,7 +1059,4 @@ sub cmp_postprocess { $self->cmp_Error($ans, "Your fraction is not reduced") if $ans->{showFractionReduceWarnings}; } -################################################################################################# -################################################################################################# - 1; diff --git a/macros/contexts/contextFunctionAssign.pl b/macros/contexts/contextFunctionAssign.pl index 2ec50a1a42..7b26b701d4 100644 --- a/macros/contexts/contextFunctionAssign.pl +++ b/macros/contexts/contextFunctionAssign.pl @@ -1,9 +1,16 @@ -###################################################################### -#Description: macro to load parserAssignment and change the error -# message to be more specific for a function. Requires -# answers be submitted in the form: -# y=formula or f(x)=formula -###################################################################### +# Note: perhaps deprecate. Not sure it is being used. + +=head1 NAME + +contextFunctionAssign.pl - allow an answer to have an function or variable assignment. + +=head1 DESCRIPTION + +This allows a answer to be a function or variable assignment change the error +message to be more specific for a function. + +=cut + loadMacros("parserAssignment.pl"); sub parser::Assignment::Formula::cmp_equal { @@ -16,6 +23,4 @@ sub parser::Assignment::Formula::cmp_equal { } } -###################################################################### - 1; diff --git a/macros/contexts/contextInequalities.pl b/macros/contexts/contextInequalities.pl index 734a6a1f53..5ee59ea76f 100644 --- a/macros/contexts/contextInequalities.pl +++ b/macros/contexts/contextInequalities.pl @@ -1,18 +1,9 @@ =head1 NAME -Context("Inequalities"), Context("Inequalities-Only") - Provides contexts that -allow intervals to be specified as inequalities. +contextInequalities.pl - Provides contexts that allow intervals to be specified as inequalities. -=head1 DESCRIPTION - -Implements contexts that provides for inequalities that produce -the cooresponding C, C or C C. There are -two such contexts: C, in which both -intervals and inequalities are defined, and C, -which allows only inequalities as a means of producing intervals. - -=head1 USAGE +=head1 SYNOPSIS loadMacros("contextInequalities.pl"); @@ -29,6 +20,15 @@ =head1 USAGE $S5 = Compute("x = 1"); # forms the Set $S6 = Compute("x != 1"); # forms the Union (-inf,1) U (1,inf) + +=head1 DESCRIPTION + +Implements contexts that provides for inequalities that produce +the cooresponding C, C or C C. There are +two such contexts: C, in which both +intervals and inequalities are defined, and C, +which allows only inequalities as a means of producing intervals. + You can set the "noneWord" flag to specify the string to use when the inequalities specify the empty set. By default, it is "NONE", but you can change it to other strings. Be sure @@ -99,9 +99,8 @@ =head1 USAGE package Inequalities; -# # Sets up the two inequality contexts -# + sub Init { my $context = $main::context{Inequalities} = Parser::Context->getCopy("Interval"); $context->{name} = "Inequalities"; @@ -233,9 +232,8 @@ sub Init { $context->{precedence}{Inequality} = $context->{precedence}{special}; $context->lists->set(List => { class => 'Inequalities::List::List' }); - # # Disable interval notation in "Inequalities-Only" context - # + $context = $main::context{"Inequalities-Only"} = $context->copy; $context->lists->set( Interval => { class => 'Inequalities::List::notAllowed' }, @@ -245,29 +243,25 @@ sub Init { $context->operators->set('U' => { class => 'Inequalities::BOP::union' }); $context->constants->remove('R'); - # # Define the Inequality() constructor - # + main::PG_restricted_eval('sub Inequality {Value->Package("Inequality")->new(@_)}'); } -################################################## -# # General BOP that handles the inequalities. # The difference comes in the _eval() method, # which tells what each computes. -# + package Inequalities::BOP::inequality; our @ISA = ("Parser::BOP"); -# # Check that the inequality is formed between a variable and a number, # or between a number and another compatible inequality. Otherwise, # give an error. -# + # varPos and numPos tell which of lop or rop is the variable and which # the number. varName is the variable involved in the inequality. -# + sub _check { my $self = shift; $self->Error("'%s' should be written '%s'", $self->{bop}, $self->{def}{isSloppy}) @@ -300,11 +294,10 @@ sub _check { $self->Error("'%s' can't be combined with '%s'", $v->{bop}, $self->{bop}); } -# # Generate the interval for the given type of inequality. # If it is a combined inequality, intersect with the other # one to get the final set. -# + sub _eval { my $self = shift; my ($a, $b) = @_; @@ -404,15 +397,13 @@ sub evalNotEqualTo { )->with(notEqual => 1); } -# # Inequalities have dummy variables that are not really # variables of a formula. sub getVariables { {} } -# # Avoid unwanted parentheses from the standard routines. -# + sub string { my ($self, $precedence) = @_; my $string; @@ -436,10 +427,8 @@ sub TeX { return $TeX; } -################################################## -# # Implements the "and" operation as set intersection -# + package Inequalities::BOP::and; our @ISA = ("Parser::BOP"); @@ -456,10 +445,8 @@ sub _check { sub _eval { $_[1]->intersect($_[2]) } -################################################## -# # Implements the "or" operation as set union -# + package Inequalities::BOP::or; our @ISA = ("Parser::BOP"); @@ -476,13 +463,11 @@ sub _check { sub _eval { $_[1] + $_[2] } -################################################## -# # Subclass of Parser::Variable that records whether # this variable has already been seen in the formula # (so that it can be removed from the formula's # variable list when used in an inequality.) -# + package Inequalities::Variable; our @ISA = ("Parser::Variable"); @@ -496,15 +481,13 @@ sub new { return $n; } -################################################## -# # A special class used for the variables in # inequalities, since they are not really # variables for the formula. (They don't need # to be substituted or given values when the # formula is evaluated, and so on.) These are # really just placeholders, here. -# + package Inequalities::DummyVariable; our @ISA = ("Parser::Item"); @@ -534,10 +517,8 @@ sub perl { return '$' . $self->{name}; } -################################################## -# # Give an error when U is used. -# + package Inequalities::BOP::union; our @ISA = ("Parser::BOP::union"); @@ -549,10 +530,8 @@ sub _check { $self->Error("Unions are not allowed in this context"); } -################################################## -# # Don't allow sums and differences of inequalities -# + package Inequalities::BOP::add; our @ISA = ("Parser::BOP::add"); @@ -563,10 +542,8 @@ sub _check { if $self->{lop}{isInequality} || $self->{rop}{isInequality}; } -################################################## -# # Don't allow sums and differences of inequalities -# + package Inequalities::BOP::subtract; our @ISA = ("Parser::BOP::subtract"); @@ -577,31 +554,23 @@ sub _check { if $self->{lop}{isInequality} || $self->{rop}{isInequality}; } -################################################## -# # For the Inequalities-Only context, report # an error for Intervals, Sets or Union notation. -# + package Inequalities::List::notAllowed; our @ISA = ("Parser::List::List"); sub _check { (shift)->Error("You are not allowed to use intervals or sets in this context") } -################################################## -################################################## -# # Subclasses of the Interval, Set, and Union classes # that stringify as inequalities -# -# # Some common routines to all three classes -# + package Inequalities::common; -# # Turn the object back into its usual Value version -# + sub demote { my $self = shift; my $context = $self->context; @@ -611,22 +580,19 @@ sub demote { $context->Package($other->type)->make($context, $other->makeData); } -# # Needed to get Interval data in the right order for make(), # and demote all the items in a Union -# + sub makeData { (shift)->value } -# # Recursively mark Intervals and Sets in a Union as Inequalities -# + sub updateParts { } -# # Demote the operands to normal Value objects and # perform the action, then remake the result into # an Inequality again. -# + sub apply { my $self = shift; my $context = $self->context; @@ -648,9 +614,8 @@ sub compare { return Value::_compare($self->demote, $self->demote($other), $flag); } -# # The name to use for error messages in answer checkers -# + sub class {"Inequality"} sub cmp_class {"an Inequality"} sub showClass {"an Inequality"} @@ -660,18 +625,16 @@ sub typeRef { return Value::Type($self->type, $self->length, $Value::Type{number}); } -# # Get the precedence based on the type rather than the class. -# + sub precedence { my $self = shift; my $precedence = $self->context->{precedence}; return $precedence->{ $self->type } - $precedence->{Interval} + $precedence->{ $self->class }; } -# # Produce better error messages for inequalities -# + sub cmp_checkUnionReduce { my $self = shift; my $student = shift; @@ -699,8 +662,6 @@ sub cmp_checkUnionReduce { } } -################################################## - package Inequalities::Interval; our @ISA = ("Inequalities::common", "Value::Interval"); @@ -748,16 +709,13 @@ sub TeX { } } -################################################## - package Inequalities::Union; our @ISA = ("Inequalities::common", "Value::Union"); sub type {"Union"} -# # Mark all the parts of the union as inequalities -# + sub updateParts { my $self = shift; foreach my $I (@{ $self->{data} }) { @@ -768,18 +726,16 @@ sub updateParts { } } -# # Update the intervals and sets when a new union is made -# + sub make { my $self = (shift)->SUPER::make(@_); $self->updateParts; return $self; } -# # Demote all the items in the union -# + sub makeData { my $self = shift; my @U = (); @@ -869,8 +825,6 @@ sub joinAnd { return join($and, @_); } -################################################## - package Inequalities::Set; our @ISA = ("Inequalities::common", "Value::Set"); @@ -915,10 +869,8 @@ sub TeX { return join('\hbox{ or }', @coords); } -################################################## -# # A class for making inequalities by hand -# + package Inequalities::Inequality; our @ISA = ('Value'); @@ -941,10 +893,8 @@ sub new { return $S; } -################################################## -# # Allow Interval() to coerce types to Value::Interval -# + package Inequalities::MakeInterval; our @ISA = ("Value::Interval"); @@ -955,10 +905,8 @@ sub new { return $self; } -################################################## -# # Mark this as a list of inequalities (if it is) -# + package Inequalities::List; our @ISA = ("Value::List"); @@ -977,10 +925,10 @@ sub _check { my $self = shift; $self->SUPER::_check(@_); if ($self->canBeInUnion) { - # + # Convert lists that look like intervals into intervals # and then check if they are OK. - # + bless $self, $self->context->{lists}{Interval}{class}; $self->{type} = $Value::Type{interval}; $self->{parens} = $self->context->{parens}{interval}; @@ -993,6 +941,4 @@ sub _check { } } -################################################## - 1; diff --git a/macros/contexts/contextInequalitiesAllowStrings.pl b/macros/contexts/contextInequalitiesAllowStrings.pl index 25166a0030..97ffb56723 100644 --- a/macros/contexts/contextInequalitiesAllowStrings.pl +++ b/macros/contexts/contextInequalitiesAllowStrings.pl @@ -1,16 +1,12 @@ +# Note: perhaps deprecate or add to inequalities as a flag. =head1 NAME -contextInequalitiesAllowStrings.pl -- extra macros for Intermediate Algebra problems at CofI +contextInequalitiesAllowStrings.pl -- allows use of R, the set of real numbers, in intervals. -=head1 Synposis +=head1 DESCRIPTION -macros by R Cruz -- The College of Idaho - -=head2 Allows string answers for the set of real numbers and the empty set - -Adds the string "All real numbers" to the Inequalities context -NOT WORKING: Adds the string "No solution" to the Inequalities context +Allows string answers for the set of real numbers and the empty set =cut @@ -38,13 +34,13 @@ sub _contextInequalitiesAllowStrings_init { #-----Add variations of "No solution" = NONE #************This part does not work. Can't get it to "take" the empty set # Tried Set(), NONE and DNE - # + # $context->constants->redefine("No solution"",from=>"Interval",using=>"{}"); # $context->constants->set("No solution"=>{TeX=>"\\mbox{No solution}"}); - # + # $context->constants->redefine("no solution"",from=>"Interval",using=>"{}"); # $context->constants->set("no solution"=>{TeX=>"\\mbox{no solution}"}); - # + # $context->constants->redefine("NO SOLUTION"",from=>"Interval",using=>"{}"); # $context->constants->set("NO SOLUTION"=>{TeX=>"\\mbox{NO SOLUTION}"}); diff --git a/macros/contexts/contextInequalitySetBuilder.pl b/macros/contexts/contextInequalitySetBuilder.pl index e0835c7360..b9cc1e659f 100644 --- a/macros/contexts/contextInequalitySetBuilder.pl +++ b/macros/contexts/contextInequalitySetBuilder.pl @@ -1,21 +1,10 @@ =head1 NAME -C, C - Provides -contexts that allow sets to be specified using set-builder notation and inequalities. +contextInequalitySetBuilder.pl - Provides contexts that allow sets to be specified using +set-builder notation and inequalities. -=head1 DESCRIPTION - -Implements contexts that provides for sets described using set-builder -notation with inequalities. (This actually is a special way of -creating Intervals, Sets, and Unions, and they can be used together -with standard interval notation.) There are two such contexts: -C, in which both intervals and sets -formed by inequalities are defined, and -C, which allows only set-builder -notation (not intervals or point sets). - -=head1 USAGE +=head1 SYNOPSIS loadMacros("contextInequalitySetBuilder.pl"); @@ -32,6 +21,17 @@ =head1 USAGE $S5 = Compute("{ x : x = 1 }"); # forms the Set {1} $S6 = Compute("{ x : x != 1 }"); # forms the Union (-inf,1) U (1,inf) +=head1 DESCRIPTION + +Implements contexts that provides for sets described using set-builder +notation with inequalities. (This actually is a special way of +creating Intervals, Sets, and Unions, and they can be used together +with standard interval notation.) There are two such contexts: +C, in which both intervals and sets +formed by inequalities are defined, and +C, which allows only set-builder +notation (not intervals or point sets). + The C contexts accept the flags for the Inequalities contexts from the C file (see its documentation for details). @@ -84,9 +84,9 @@ =head1 USAGE package InequalitySetBuilder; sub Init { - # + # Make a new context from an old one and add SetBuilder notation - # + my $addSetBuilder = sub { my ($new, $old) = @_; my $context = $main::context{$new} = Parser::Context->getCopy($old); @@ -118,15 +118,13 @@ sub Init { return $context; }; - # # Make the two new contexts - # + &{$addSetBuilder}("InequalitySetBuilder", "Inequalities"); &{$addSetBuilder}("InequalitySetBuilder-Only", "Inequalities-Only")->flags->set(noSets => 1); - # # Define the SetBuilder() constructor - # + main::PG_restricted_eval('sub SetBuilder {Value->Package("SetBuilder")->new(@_)}'); } @@ -152,10 +150,8 @@ sub UseVerticalSuchThat { &{$adjust}("InequalitySetBuilder-Only"); } -################################################## -# # A class for making set-builder sets by hand -# + package InequalitySetBuilder::SetBuilder; our @ISA = ('Value'); @@ -178,12 +174,9 @@ sub new { return $S; } -################################################## -################################################## -# # The Parser object that holds the set-builder notation # (and also allows point-set notation) -# + package InequalitySetBuilder::List::Set; our @ISA = ('Parser::List::Set'); @@ -216,11 +209,8 @@ sub eval { sub canBeInUnion {1} -################################################## -################################################## -# # The such-that operator -# + package InequalitySetBuilder::BOP::suchthat; our @ISA = ('Parser::BOP'); @@ -238,18 +228,15 @@ sub _check { $self->{lop} = Inequalities::DummyVariable->new($self->{equation}, $self->{lop}{name}, $self->{lop}{ref}); } -# # Make sure it is only used in set braces -# + sub eval { my $self = shift; $self->Error("'%s' can only appear within set-builder notation (did you forget braces?)", $self->{bop}); } -################################################## -# # Give a warning about adding sets -# + package InequalitySetBuilder::BOP::add; our @ISA = ('Inequalities::BOP::add'); @@ -260,10 +247,8 @@ sub _check { if $self->{lop}{isSetBuilder} || $self->{rop}{isSetBuilder}; } -################################################## -# # Handle subtraction of sets -# + package InequalitySetBuilder::BOP::subtract; our @ISA = ("Inequalities::BOP::subtract"); @@ -273,10 +258,8 @@ sub _check { else { $self->SUPER::_check(@_) } } -################################################## -# # Handle unions of sets -# + package InequalitySetBuilder::BOP::union; our @ISA = ("Parser::BOP::union"); @@ -286,11 +269,7 @@ sub _check { else { $self->SUPER::_check(@_) } } -################################################## -################################################## -# # Common function for the classes below -# package InequalitySetBuilder::common; our @ISA = (); @@ -336,11 +315,9 @@ sub _typeMatch { sub cmp_class {"a Set in Set-Builder Notation"} sub showClass {"a Set in Set-Builder Notation"} -################################################## -# # Special Inequalities::Interval subclass that # prints using set-builder notation. -# + package InequalitySetBuilder::Interval; our @ISA = ('InequalitySetBuilder::common', 'Inequalities::Interval'); @@ -355,11 +332,8 @@ sub typeMatch { $self->_typeMatch($other, $self->SUPER::typeMatch($other)); } -################################################## -# # Special Inequalities::Union subclass that # prints using set-builder notation. -# package InequalitySetBuilder::Union; our @ISA = ('InequalitySetBuilder::common', 'Inequalities::Union'); @@ -375,11 +349,8 @@ sub typeMatch { $self->_typeMatch($other, $self->SUPER::typeMatch($other)); } -################################################## -# # Special Inequalities::Set subclass that # prints using set-builder notation. -# package InequalitySetBuilder::Set; our @ISA = ('InequalitySetBuilder::common', 'Inequalities::Set'); @@ -395,6 +366,4 @@ sub typeMatch { $self->_typeMatch($other, $self->SUPER::typeMatch($other)); } -################################################## - 1; diff --git a/macros/contexts/contextInteger.pl b/macros/contexts/contextInteger.pl index 8ee01d8f74..e2fce5c0f8 100644 --- a/macros/contexts/contextInteger.pl +++ b/macros/contexts/contextInteger.pl @@ -1,3 +1,4 @@ +#Note: this doesn't appear to be a context--rather just a list of additional functions. =head1 NAME @@ -8,7 +9,7 @@ =head1 DESCRIPTION This is a Parser context that adds integer related functions. This forces students to only enter integers as their answers. -=head1 USAGE +=head1 SYNOPSIS Context("Integer") @@ -46,19 +47,42 @@ =head1 USAGE $randomPrime = randomPrime(100, 1000); +=head1 FUNCTIONS + +=head2 primeFactorization + +Find the prime factorization of an integer. + +=head2 gcd + +Find the greatest common divisor + +=head2 lcm + +Find the lowest common multiple. + +=head2 phi + +Find phi. + +=head2 tau + +Find tau. + +=head2 isPrime + +Determine if the given integer is prime. + =cut loadMacros('MathObjects.pl'); sub _contextInteger_init { context::Integer::Init() } -########################################################################### - package context::Integer; -# # Initialize the contexts and make the creator function. -# + sub Init { my $context = $main::context{Integer} = Parser::Context->getCopy("Numeric"); $context->{name} = "Integer"; @@ -92,9 +116,8 @@ sub Init { main::PG_restricted_eval("sub gcd {context::Integer::Function::Numeric2::gcd(\@_)}"); } -# # divisor function -# + sub _divisor { my $power = abs(shift); my $a = abs(shift); @@ -141,9 +164,8 @@ sub _getPrimesInRange { package context::Integer::Function::Numeric; our @ISA = qw(Parser::Function::numeric); # checks for 2 numeric inputs -# # Prime Factorization -# + sub primeFactorization { my $a = abs(shift); $self->Error("Cannot factor Zero into primes.") if $a == 0; @@ -169,9 +191,8 @@ sub primeFactorization { return @results; } -# # Euler's totient function phi(n) -# + sub phi { my $a = abs(shift); $self->Error("Cannot phi on Zero.") if $a == 0; @@ -188,9 +209,8 @@ sub phi { return $result; } -# # number of divisors function tau(n) -# + sub tau { my $a = shift; return context::Integer::_divisor(0, $a); @@ -217,9 +237,8 @@ sub randomPrime { package context::Integer::Function::Numeric2; our @ISA = qw(Parser::Function::numeric2); # checks for 2 numeric inputs -# # Greatest Common Divisor -# + sub gcd { my $a = abs(shift); my $b = abs(shift); @@ -232,9 +251,8 @@ sub gcd { return $b; } -# # Extended Greatest Common Divisor -# + # return (g, x, y) a*x + b*y = gcd(x, y) sub egcd { my $a = shift; @@ -249,9 +267,8 @@ sub egcd { } } -# # Modular inverse -# + # x = mulinv(b) mod n, (x * b) % n == 1 sub mulularInverse { my $b = shift; @@ -264,9 +281,8 @@ sub mulularInverse { } } -# # Least Common Multiple -# + sub lcm { my $a = abs(shift); my $b = abs(shift); diff --git a/macros/contexts/contextIntegerFunctions.pl b/macros/contexts/contextIntegerFunctions.pl index 03fafee8bb..355bf6603c 100644 --- a/macros/contexts/contextIntegerFunctions.pl +++ b/macros/contexts/contextIntegerFunctions.pl @@ -1,3 +1,5 @@ +# Note: the way this is used, it appears that want to allow P and C to be used by +# authors but not students, so why is this a context? =head1 NAME @@ -14,7 +16,7 @@ =head1 DESCRIPTION C(n,r) and P(n,r) functions. Problems which do permit this should alert the student in their text. -=head1 USAGE +=head1 SYNOPSISS Context("IntegerFunctions") diff --git a/macros/contexts/contextLeadingZero.pl b/macros/contexts/contextLeadingZero.pl index 428cc0a648..4ad1fad82a 100644 --- a/macros/contexts/contextLeadingZero.pl +++ b/macros/contexts/contextLeadingZero.pl @@ -1,3 +1,15 @@ +# Note: does this need to be a separate context? Perhaps a flag in the LimitedNumeric context? + +=head1 NAME + +contextLeadingZero.pl - Require numeric answers to have a 0 before the decimal point. + +=head1 DESCRIPTION + +Require numeric answers to have a 0 before the decimal point. + +=cut + loadMacros("contextLimitedNumeric.pl"); $context{LeadingZero} = Parser::Context->getCopy("LimitedNumeric"); diff --git a/macros/contexts/contextLimitedComplex.pl b/macros/contexts/contextLimitedComplex.pl index ea44d15cc1..7630aea7b0 100644 --- a/macros/contexts/contextLimitedComplex.pl +++ b/macros/contexts/contextLimitedComplex.pl @@ -6,7 +6,10 @@ =head1 NAME =head1 DESCRIPTION Implements a context in which complex numbers can be entered, -but no complex operations are permitted. So students will +but no complex operations are permitted. + +Implements a context in which complex numbers can be entered, +but no complex operations are permitted. So students will be able to perform operations within the real and imaginary parts of the complex numbers, but not between complex numbers. @@ -49,17 +52,14 @@ =head1 DESCRIPTION sub _contextLimitedComplex_init { LimitedComplex::Init() }; # don't load it again -################################################## -# # Handle common checking for BOPs -# + package LimitedComplex::BOP; -# # Do original check and then if the operands are numbers, its OK. # Otherwise, do an operator-specific check for if complex numbers are OK. # Otherwise report an error. -# + sub _check { my $self = shift; my $super = ref($self); @@ -77,14 +77,12 @@ sub _check { $self->Error("Your answer should be of the form %s", $self->theForm); } -# # filled in by subclasses -# + sub checkComplex { return 0 } -# # Get the form for use in error messages -# + sub theForm { my $self = shift; my $format = $self->context->{flags}{complex_format}; @@ -93,15 +91,12 @@ sub theForm { return 'a+bi or a*e^(bi)'; } -############################################## -# # Now we get the individual replacements for the operators # that we don't want to allow. We inherit everything from # the original Parser::BOP class, and just add the # complex checks here. Note that checkComplex only # gets called if exactly one of the terms is complex # and the other is real. -# package LimitedComplex::BOP::add; our @ISA = qw(LimitedComplex::BOP Parser::BOP::add); @@ -117,8 +112,6 @@ sub checkComplex { || ($r->class eq 'Complex' && $r->{value}[0] == 0); } -############################################## - package LimitedComplex::BOP::subtract; our @ISA = qw(LimitedComplex::BOP Parser::BOP::subtract); @@ -133,8 +126,6 @@ sub checkComplex { || ($r->class eq 'Complex' && $r->{value}[0] == 0); } -############################################## - package LimitedComplex::BOP::multiply; our @ISA = qw(LimitedComplex::BOP Parser::BOP::multiply); @@ -146,20 +137,15 @@ sub checkComplex { && ($r->class eq 'Constant' || $r->isRealNumber || $r->{isPower})); } -############################################## - package LimitedComplex::BOP::divide; our @ISA = qw(LimitedComplex::BOP Parser::BOP::divide); -############################################## - package LimitedComplex::BOP::power; our @ISA = qw(LimitedComplex::BOP Parser::BOP::power); -# # Base must be 'e' (then we know the other is the complex # since we only get here if exactly one term is complex) -# + sub checkComplex { my $self = shift; return 0 if $self->context->{flags}{complex_format} eq 'cartesian'; @@ -177,11 +163,7 @@ sub checkComplex { $self->Error("Exponentials can only be of the form 'e^(ai)' in this context"); } -############################################## -############################################## -# # Now we do the same for the unary operators -# package LimitedComplex::UOP; @@ -206,22 +188,14 @@ sub _check { sub theForm { LimitedComplex::BOP::theForm(@_) } -############################################## - package LimitedComplex::UOP::plus; our @ISA = qw(LimitedComplex::UOP Parser::UOP::plus); -############################################## - package LimitedComplex::UOP::minus; our @ISA = qw(LimitedComplex::UOP Parser::UOP::minus); -############################################## -############################################## -# # Absolute value does complex norm, so we # trap that as well. -# package LimitedComplex::List::AbsoluteValue; our @ISA = qw(Parser::List::AbsoluteValue); @@ -233,17 +207,12 @@ sub _check { $self->Error("Can't take absolute value of Complex Numbers in this context"); } -############################################## -############################################## - package LimitedComplex; sub Init { - # # Build the new context that calls the # above classes rather than the usual ones - # my $context = $main::context{LimitedComplex} = Parser::Context->getCopy("Complex"); $context->{name} = "LimitedComplex"; @@ -262,48 +231,36 @@ sub Init { 'u+' => { class => 'LimitedComplex::UOP::plus' }, 'u-' => { class => 'LimitedComplex::UOP::minus' }, ); - # + # Remove these operators and functions - # + $context->lists->set(AbsoluteValue => { class => 'LimitedComplex::List::AbsoluteValue' },); $context->operators->undefine('_', 'U'); $context->functions->disable('Complex'); foreach my $fn ($context->functions->names) { $context->{functions}{$fn}{nocomplex} = 1 } - # + # Format can be 'cartesian', 'polar', or 'either' - # - $context->flags->set(complex_format => 'either'); - ######################### + $context->flags->set(complex_format => 'either'); $context = $main::context{'LimitedComplex-cartesian'} = $main::context{LimitedComplex}->copy; $context->flags->set(complex_format => 'cartesian'); - ######################### - $context = $main::context{'LimitedComplex-polar'} = $main::context{LimitedComplex}->copy; $context->flags->set(complex_format => 'polar'); - ######################### - $context = $main::context{'LimitedComplex-cartesian-strict'} = $main::context{'LimitedComplex-cartesian'}->copy; $context->flags->set(strict_numeric => 1); $context->functions->disable('All'); - ######################### - $context = $main::context{'LimitedComplex-polar-strict'} = $main::context{'LimitedComplex-polar'}->copy; $context->flags->set(strict_numeric => 1); $context->functions->disable('All'); - ######################### - $context = $main::context{'LimitedComplex-strict'} = $main::context{'LimitedComplex'}->copy; $context->flags->set(strict_numeric => 1); $context->functions->disable('All'); - ######################### - main::Context("LimitedComplex"); ### FIXME: probably should require the author to set this explicitly } diff --git a/macros/contexts/contextLimitedFactor.pl b/macros/contexts/contextLimitedFactor.pl index 47d0df8d0b..702fee209f 100644 --- a/macros/contexts/contextLimitedFactor.pl +++ b/macros/contexts/contextLimitedFactor.pl @@ -1,28 +1,24 @@ =head1 NAME -contextLimitedFactor.pl - Context file to check that the students answer agrees in form +contextLimitedFactor.pl - Context file to check that the students answer agrees in form with a factored polynomial =head1 DESCRIPTION -Answers are first compared as usual, and if they agree, then bizarroArithmetic.pl turns +Answers are first compared as usual, and if they agree, then bizarroArithmetic.pl turns on bizarro addition, subtraction, and division. This, for example, will cause (x+2)(x+1) to evaluate differently than x^2+2x+1. -The flag factorableObject defaults to 'polynomial', but it could be set to say, +The flag factorableObject defaults to 'polynomial', but it could be set to say, 'rational expression', etc. It is used in error messages. =cut -loadMacros( - "bizarroArithmetic.pl", +loadMacros("bizarroArithmetic.pl"); -); - -# # Set up the LimitedFactor context -# + sub _contextLimitedFactor_init { my $context = $main::context{LimitedFactor} = Parser::Context->getCopy("Numeric"); $context->operators->set( diff --git a/macros/contexts/contextLimitedNumeric.pl b/macros/contexts/contextLimitedNumeric.pl index 99ce798672..1545c27f6d 100644 --- a/macros/contexts/contextLimitedNumeric.pl +++ b/macros/contexts/contextLimitedNumeric.pl @@ -1,3 +1,5 @@ +# Is this duplicated by Parser::Legacy::LimitedNumeric? +# If so, remove? =head1 NAME @@ -5,18 +7,15 @@ =head1 NAME =head1 DESCRIPTION -Implements a context in which numbers can be entered, -but no operations are permitted between them. +Implements a context in which numbers can be entered, but no operations are permitted between them. -There are two versions: one for lists of numbers -and one for a single number. Select them using +There are two versions: one for lists of numbers and one for a single number. Select them using one of the following commands: Context("LimitedNumeric-List"); Context("LimitedNumeric"); -(Now uses Parser::Legacy::LimitedNumeric to implement -these contexts.) +(Now uses Parser::Legacy::LimitedNumeric to implement these contexts.) =cut diff --git a/macros/contexts/contextLimitedPoint.pl b/macros/contexts/contextLimitedPoint.pl index fd7ffaa3b1..f11bdf137a 100644 --- a/macros/contexts/contextLimitedPoint.pl +++ b/macros/contexts/contextLimitedPoint.pl @@ -18,16 +18,13 @@ =head1 DESCRIPTION sub _contextLimitedPoint_init { LimitedPoint::Init() }; # don't load it again -################################################## -# # Handle common checking for BOPs -# + package LimitedPoint::BOP; -# # Do original check and then if the operands are numbers, its OK. # Otherwise report an error. -# + sub _check { my $self = shift; my $super = ref($self); @@ -38,37 +35,24 @@ sub _check { $self->Error("In this context, '%s' can only be used with Numbers", $bop); } -############################################## -# # Now we get the individual replacements for the operators # that we don't want to allow. We inherit everything from # the original Parser::BOP class, except the _check # routine, which comes from LimitedPoint::BOP above. -# package LimitedPoint::BOP::add; our @ISA = qw(LimitedPoint::BOP Parser::BOP::add); -############################################## - package LimitedPoint::BOP::subtract; our @ISA = qw(LimitedPoint::BOP Parser::BOP::subtract); -############################################## - package LimitedPoint::BOP::multiply; our @ISA = qw(LimitedPoint::BOP Parser::BOP::multiply); -############################################## - package LimitedPoint::BOP::divide; our @ISA = qw(LimitedPoint::BOP Parser::BOP::divide); -############################################## -############################################## -# # Now we do the same for the unary operators -# package LimitedPoint::UOP; @@ -82,22 +66,14 @@ sub _check { $self->Error("In this context, '%s' can only be used with Numbers", $uop); } -############################################## - package LimitedPoint::UOP::plus; our @ISA = qw(LimitedPoint::UOP Parser::UOP::plus); -############################################## - package LimitedPoint::UOP::minus; our @ISA = qw(LimitedPoint::UOP Parser::UOP::minus); -############################################## -############################################## -# # Absolute value does vector norm, so we # trap that as well. -# package LimitedPoint::List::AbsoluteValue; our @ISA = qw(Parser::List::AbsoluteValue); @@ -109,16 +85,12 @@ sub _check { $self->Error("Vector norm is not allowed in this context"); } -############################################## -############################################## - package LimitedPoint; sub Init { - # + # Build the new context that calls the # above classes rather than the usual ones - # my $context = $main::context{LimitedPoint} = Parser::Context->getCopy("Point"); $context->{name} = "LimitedPoint"; @@ -135,9 +107,9 @@ sub Init { 'u+' => { class => 'LimitedPoint::UOP::plus' }, 'u-' => { class => 'LimitedPoint::UOP::minus' }, ); - # + # Remove these operators and functions - # + $context->operators->undefine('_', 'U', '><', '.'); $context->functions->undefine('norm', 'unit'); $context->lists->set(AbsoluteValue => { class => 'LimitedPoint::List::AbsoluteValue' },); diff --git a/macros/contexts/contextLimitedPolynomial.pl b/macros/contexts/contextLimitedPolynomial.pl index 8720b6e9f3..7b48c0649c 100644 --- a/macros/contexts/contextLimitedPolynomial.pl +++ b/macros/contexts/contextLimitedPolynomial.pl @@ -1,7 +1,7 @@ =head1 NAME -contextLimitedPolynomial.pl - Allow only entry of polynomials. +contextLimitedPolynomial.pl - Allow only entry of polynomials in multiple forms. =head1 DESCRIPTION @@ -34,18 +34,14 @@ =head1 DESCRIPTION sub _contextLimitedPolynomial_init { LimitedPolynomial::Init() }; # don't load it again -################################################## -# # Handle common checking for BOPs -# package LimitedPolynomial; -# # Mark a variable as having power 1 # Mark a number as being present (when strict coefficients are used) # Mark a monomial as having its given powers -# + sub markPowers { my $self = shift; if ($self->class eq 'Variable') { @@ -63,10 +59,9 @@ sub markPowers { } } -# # Get a hash of variable names that point to indices # within the array of powers for a monomial -# + sub getVarIndex { my $self = shift; my $equation = $self->{equation}; @@ -78,28 +73,22 @@ sub getVarIndex { return $equation->{varIndex}; } -# # Check for a constant expression -# + sub isConstant { my $self = shift; return 1 if $self->{isConstant} || $self->class eq 'Constant'; return scalar(keys(%{ $self->getVariables })) == 0; } -################################################## -# # Handle common checking for BOPs -# package LimitedPolynomial::BOP; our @ISA = (); -# # Do original check and then if the operands are numbers, its OK. # Otherwise, do an operator-specific check for if the polynomial is OK. # Otherwise report an error. -# sub _check { my $self = shift; @@ -117,15 +106,13 @@ sub _check { $self->Error("Your answer doesn't look like a simplified polynomial"); } -# # filled in by subclasses -# + sub checkPolynomial { return 0 } -# # Check that the exponents of a monomial are OK # and record the new exponent array -# + sub checkExponents { my $self = shift; my ($l, $r) = ($self->{lop}, $self->{rop}); @@ -149,10 +136,9 @@ sub checkExponents { return 1; } -# # Check that the powers of combined monomials are OK # and record the new power list -# + sub checkPowers { my $self = shift; my ($l, $r) = ($self->{lop}, $self->{rop}); @@ -173,24 +159,20 @@ sub checkPowers { return 1; } -# # Report an error when both operands are constants # and strictCoefficients is in effect. -# + sub checkStrict { my $self = shift; $self->Error("Can't use '%s' between constants", $self->{bop}); } -############################################## -# # Now we get the individual replacements for the operators # that we don't want to allow. We inherit everything from # the original Parser::BOP class, and just add the # polynomial checks here. Note that checkPolynomial # only gets called if at least one of the terms is not # a number. -# package LimitedPolynomial::BOP::add; our @ISA = qw(LimitedPolynomial::BOP Parser::BOP::add); @@ -202,8 +184,6 @@ sub checkPolynomial { $self->checkPowers; } -############################################## - package LimitedPolynomial::BOP::subtract; our @ISA = qw(LimitedPolynomial::BOP Parser::BOP::subtract); @@ -214,8 +194,6 @@ sub checkPolynomial { $self->checkPowers; } -############################################## - package LimitedPolynomial::BOP::multiply; our @ISA = qw(LimitedPolynomial::BOP Parser::BOP::multiply); @@ -239,8 +217,6 @@ sub checkStrict { $self->Error("You can only use '%s' between coefficents and variables in a simplified polynomial", $self->{bop}); } -############################################## - package LimitedPolynomial::BOP::divide; our @ISA = qw(LimitedPolynomial::BOP Parser::BOP::divide); @@ -265,8 +241,6 @@ sub checkStrict { $self->Error("You can only use '%s' to form numeric fractions", $self->{bop}) if $self->{lop}->class eq 'BOP'; } -############################################## - package LimitedPolynomial::BOP::power; our @ISA = qw(LimitedPolynomial::BOP Parser::BOP::power); @@ -295,11 +269,7 @@ sub checkStrict { $self->Error("You can only use powers of a variable in a simplified polynomial"); } -############################################## -############################################## -# # Now we do the same for the unary operators -# package LimitedPolynomial::UOP; @@ -323,21 +293,13 @@ sub _check { sub checkPolynomial { return !(shift)->{op}{isPoly} } -############################################## - package LimitedPolynomial::UOP::plus; our @ISA = qw(LimitedPolynomial::UOP Parser::UOP::plus); -############################################## - package LimitedPolynomial::UOP::minus; our @ISA = qw(LimitedPolynomial::UOP Parser::UOP::minus); -############################################## -############################################## -# # Don't allow absolute values -# package LimitedPolynomial::List::AbsoluteValue; our @ISA = qw(Parser::List::AbsoluteValue); @@ -349,11 +311,7 @@ sub _check { $self->Error("Can't use absolute values in polynomials"); } -############################################## -############################################## -# # Only allow numeric function calls -# package LimitedPolynomial::Function; @@ -376,16 +334,12 @@ package LimitedPolynomial::Function::trig; package LimitedPolynomial::Function::hyperbolic; our @ISA = qw(LimitedPolynomial::Function Parser::Function::hyperbolic); -############################################## -############################################## - package LimitedPolynomial; sub Init { - # + # Build the new context that calls the # above classes rather than the usual ones - # my $context = $main::context{LimitedPolynomial} = Parser::Context->getCopy("Numeric"); $context->{name} = "LimitedPolynomial"; @@ -404,15 +358,15 @@ sub Init { 'u+' => { class => 'LimitedPolynomial::UOP::plus' }, 'u-' => { class => 'LimitedPolynomial::UOP::minus' }, ); - # + # Remove these operators and functions - # + $context->lists->set(AbsoluteValue => { class => 'LimitedPolynomial::List::AbsoluteValue' },); $context->operators->undefine('_', '!', 'U'); $context->functions->disable("atan2"); - # + # Hook into the numeric, trig, and hyperbolic functions - # + foreach ('ln', 'log', 'log10', 'exp', 'sqrt', 'abs', 'int', 'sgn') { $context->functions->set("$_" => { class => 'LimitedPolynomial::Function::numeric' }); } @@ -422,14 +376,13 @@ sub Init { "${_}h" => { class => 'LimitedPolynomial::Function::hyperbolic' } ); } - # + # Don't convert -ax-b to -(ax+b), or -ax+b to b-ax, etc. - # + $context->reduction->set("(-x)-y" => 0, "(-x)+y" => 0); - # # A context where coefficients can't include operations - # + $context = $main::context{"LimitedPolynomial-Strict"} = $context->copy; $context->flags->set(strictCoefficients => 1, singlePowers => 1, reduceConstants => 0); $context->functions->disable("All"); # can be re-enabled if needed diff --git a/macros/contexts/contextLimitedPowers.pl b/macros/contexts/contextLimitedPowers.pl index 1009a29a8c..ec13bf5ec1 100644 --- a/macros/contexts/contextLimitedPowers.pl +++ b/macros/contexts/contextLimitedPowers.pl @@ -130,9 +130,8 @@ sub OnlyNonTrivialPositiveIntegers { OnlyIntegers($context, minPower => 2, message => "integer constants bigger than 1", @_); } -# # Test for whether the power is an integer in the specified range -# + sub isInteger { my $self = shift; my $n = shift; @@ -142,9 +141,8 @@ sub isInteger { return Value::Real->make($n - int($n)) == 0; } -# # Legacy code to accommodate older approach to setting the operators -# + our @NoBaseE = ( '^' => { class => 'LimitedPowers::NoBaseE', isCommand => 1, perl => 'LimitedPowers::NoBaseE->_eval' }, '**' => { class => 'LimitedPowers::NoBaseE', isCommand => 1, perl => 'LimitedPowers::NoBaseE->_eval' }, @@ -166,8 +164,6 @@ sub isInteger { '**' => { class => 'LimitedPowers::OnlyIntegers', minPower => 2, message => "integer constants bigger than 1" }, ); -################################################## - package LimitedPowers::NoBaseE; @ISA = qw(Parser::BOP::power); @@ -185,8 +181,6 @@ sub _eval { $self->SUPER::_eval(@_); } -################################################## - package LimitedPowers::OnlyIntegers; @ISA = qw(Parser::BOP::power); @@ -200,6 +194,4 @@ sub _check { if $p->type ne 'Number' || !$p->{isConstant} || !&{$checker}($self, $p->eval); } -################################################## - 1; diff --git a/macros/contexts/contextLimitedRadical.pl b/macros/contexts/contextLimitedRadical.pl index 49569d2ecd..a473fd9ca1 100644 --- a/macros/contexts/contextLimitedRadical.pl +++ b/macros/contexts/contextLimitedRadical.pl @@ -1,60 +1,60 @@ =head1 NAME -contextLimitedRadical.pl - defines a root(n,x) function for n-th root of x, and +contextLimitedRadical.pl - defines a root(n,x) function for n-th root of x, and allows for specification of forms of radical answers, like simplified radicals or with rational denominators =head1 DESCRIPTION -This file enables a context LimitedRadical in which students and pg-authors may use -root(n,x) for the nth root of x. The function makes sure n!=0, and also allows for +This file enables a context LimitedRadical in which students and pg-authors may use +root(n,x) for the nth root of x. The function makes sure n != 0, and also allows for negative x only if n is an odd integer. -By default, the limits for Formula answer checking are [0,5] to avoid negatives in -radicals. If it is important to distinguish sqrt(x^2) as |x| rather than x, then the +By default, the limits for Formula answer checking are [0,5] to avoid negatives in +radicals. If it is important to distinguish sqrt(x^2) as |x| rather than x, then the limits should be changed to include a region where they differ. -The context requires that radical expressions (using either sqrt() or root()) meet -the form of the author's answer with respect to simplification and rationalization +The context requires that radical expressions (using either sqrt() or root()) meet +the form of the author's answer with respect to simplification and rationalization of denominators. -To accomplish this, Math Objects like "root(3,2)" should be created as Formula("root(3,2)"), -not Compute("root(3,2)"), or they will be treated as Reals and evaluated as decimals. +To accomplish this, Math Objects like "root(3,2)" should be created as Formula("root(3,2)"), +not Compute("root(3,2)"), or they will be treated as Reals and evaluated as decimals. Compute("root(3,x)") should be fine though, since it is unambiguously a Formula. -Student answers are first compared to the correct answer in the usual way to see if -they are at least numerically correct. Then to check that expressions are fully -simplified, during a check, both sqrt(x) and root(n,x) are temporarily replaced by certain -other functions. Also +, -, *, and / are temporarily replaced with bizarro arithmetic -(from bizarroArithmetic.pl) that nearly make for a bizarro field structure on R. -If the student and author answers disagree after this change, then the student's answer +Student answers are first compared to the correct answer in the usual way to see if +they are at least numerically correct. Then to check that expressions are fully +simplified, during a check, both sqrt(x) and root(n,x) are temporarily replaced by certain +other functions. Also +, -, *, and / are temporarily replaced with bizarro arithmetic +(from bizarroArithmetic.pl) that nearly make for a bizarro field structure on R. +If the student and author answers disagree after this change, then the student's answer is not in form of the author's answer. -For example "1+2" is not equivalent to "3" under bizarro addition. "2sqrt(2)" is not -equivalent to "sqrt(8)" with the bizarro arithmetic. Any radical applied to 1 is declared +For example "1+2" is not equivalent to "3" under bizarro addition. "2sqrt(2)" is not +equivalent to "sqrt(8)" with the bizarro arithmetic. Any radical applied to 1 is declared unsimplified as well. -If a student's answer is numerically equal to the author's, but not equal under bizarro -arithmetic, students get the message that their answer is not fully simplified. So care +If a student's answer is numerically equal to the author's, but not equal under bizarro +arithmetic, students get the message that their answer is not fully simplified. So care should be taken by the problem author when defining answers. -The near-field structure of the bizarro versions means that "1+sqrt(2)+sqrt(3)" can be -entered as "sqrt(3)+sqrt(2)+1", etc, and not be declared "unsimplified". Also "(1+sqrt(2))/2" -can be entered as "1/2+sqrt(2)/2" without being declared "unsimplified". However, -"(1+2sqrt(2))/2" *will* be declared different from "1/2+sqrt(2)", even though both are -generally considered fully simplified. If an author can foresee this arising, consider +The near-field structure of the bizarro versions means that "1+sqrt(2)+sqrt(3)" can be +entered as "sqrt(3)+sqrt(2)+1", etc, and not be declared "unsimplified". Also "(1+sqrt(2))/2" +can be entered as "1/2+sqrt(2)/2" without being declared "unsimplified". However, +"(1+2sqrt(2))/2" *will* be declared different from "1/2+sqrt(2)", even though both are +generally considered fully simplified. If an author can foresee this arising, consider using parserOneOf.pl to allow for multiple forms of the correct answer. -Technically both "sqrt(3)/3" and "1/sqrt(3)" are fully simplified, although you may want -rational denominators. This context will declare them equal but not equivalent. The author -should either accept both as correct using parserOneOf.pl, or give the message that the +Technically both "sqrt(3)/3" and "1/sqrt(3)" are fully simplified, although you may want +rational denominators. This context will declare them equal but not equivalent. The author +should either accept both as correct using parserOneOf.pl, or give the message that the student's answer does not have a rational denominator using answerHints.pl. -Note that there is nothing here that is actually doing any reducing of radical quantities -or honestly checking for "simplified" answers - so authors need to make sure their answers -are reduced and simplified. Also if the correct answer is "sqrt(2)" and the student -enters "sqrt(3)+sqrt(3)" or "4sqrt(2)/2", they will just be told they are wrong, not that +Note that there is nothing here that is actually doing any reducing of radical quantities +or honestly checking for "simplified" answers - so authors need to make sure their answers +are reduced and simplified. Also if the correct answer is "sqrt(2)" and the student +enters "sqrt(3)+sqrt(3)" or "4sqrt(2)/2", they will just be told they are wrong, not that their (incorrect) answer is unsimplified. diff --git a/macros/contexts/contextLimitedRadicalComplex.pl b/macros/contexts/contextLimitedRadicalComplex.pl index 235e21c93e..a6a3cd6956 100644 --- a/macros/contexts/contextLimitedRadicalComplex.pl +++ b/macros/contexts/contextLimitedRadicalComplex.pl @@ -66,9 +66,8 @@ =head1 DESCRIPTION ); -# # Set up the LimitedRadical context -# + sub _contextLimitedRadicalComplex_init { my $context = $main::context{LimitedRadicalComplex} = Parser::Context->getCopy("Complex"); Parser::Number::NoDecimals($context); @@ -128,10 +127,7 @@ sub _contextLimitedRadicalComplex_init { }; } -########################### -# # Create root(n, x) -# package my::Function::numeric2; our @ISA = ('Parser::Function::numeric2'); @@ -157,16 +153,13 @@ sub TeX { return '\sqrt[' . $n->TeX . "]{" . $x->TeX . "}"; } -########################### -# # Subclass the numeric functions -# + package my::Function::numeric; our @ISA = ('Parser::Function::numeric'); -# # Override sqrt() to return a special value times x when evaluated -# + sub sqrt { my $self = shift; my $x = shift; diff --git a/macros/contexts/contextLimitedVector.pl b/macros/contexts/contextLimitedVector.pl index 0e0f5c79ae..32dc42db0f 100644 --- a/macros/contexts/contextLimitedVector.pl +++ b/macros/contexts/contextLimitedVector.pl @@ -31,18 +31,15 @@ =head1 DESCRIPTION sub _contextLimitedVector_init { LimitedVector::Init() }; # don't load it again -################################################## -# # Handle common checking for BOPs -# + package LimitedVector::BOP; -# # Do original check and then if the operands are numbers, its OK. # Otherwise, check if there is a duplicate constant from either term # Otherwise, do an operator-specific check for if vectors are OK. # Otherwise report an error. -# + sub _check { my $self = shift; my $super = ref($self); @@ -60,15 +57,13 @@ sub _check { $self->Error("In this context, '%s' can only be used with Numbers or i,j and k", $bop); } -# # filled in by subclasses -# + sub checkVectors { return 0 } -# # Check if a constant has been repeated # (we maintain a hash that lists if one is below us in the parse tree) -# + sub checkConstants { my $self = shift; my $op = shift; @@ -87,13 +82,10 @@ sub checkConstants { if $duplicate; } -############################################## -# # Now we get the individual replacements for the operators # that we don't want to allow. We inherit everything from # the original Parser::BOP class, and just add the # vector checks here. -# package LimitedVector::BOP::add; our @ISA = qw(LimitedVector::BOP Parser::BOP::add); @@ -104,8 +96,6 @@ sub checkVectors { && ($self->{rop}->class eq 'Constant' || $self->{rop}->class =~ m/[BU]OP/)); } -############################################## - package LimitedVector::BOP::subtract; our @ISA = qw(LimitedVector::BOP Parser::BOP::subtract); @@ -115,8 +105,6 @@ sub checkVectors { && ($self->{rop}->class eq 'Constant' || $self->{rop}->class =~ m/[BU]OP/)); } -############################################## - package LimitedVector::BOP::multiply; our @ISA = qw(LimitedVector::BOP Parser::BOP::multiply); @@ -126,8 +114,6 @@ sub checkVectors { && ($self->{rop}->class eq 'Constant' || $self->{rop}->type eq 'Number')); } -############################################## - package LimitedVector::BOP::divide; our @ISA = qw(LimitedVector::BOP Parser::BOP::divide); @@ -137,11 +123,7 @@ sub checkVectors { $self->Error("In this context, '%s' can only be used with Numbers", $bop); } -############################################## -############################################## -# # Now we do the same for the unary operators -# package LimitedVector::UOP; @@ -163,26 +145,18 @@ sub _check { sub checkVector { return 0 } -############################################## - package LimitedVector::UOP::plus; our @ISA = qw(LimitedVector::UOP Parser::UOP::plus); sub checkVector { return shift->{op}->class eq 'Constant' } -############################################## - package LimitedVector::UOP::minus; our @ISA = qw(LimitedVector::UOP Parser::UOP::minus); sub checkVector { return shift->{op}->class eq 'Constant' } -############################################## -############################################## -# # Absolute value does vector norm, so we # trap that as well. -# package LimitedVector::List::AbsoluteValue; our @ISA = qw(Parser::List::AbsoluteValue); @@ -194,8 +168,6 @@ sub _check { $self->Error("Vector norm is not allowed in this context"); } -############################################## - package LimitedVector::List::Vector; our @ISA = qw(Parser::List::Vector); @@ -206,16 +178,12 @@ sub _check { $self->Error("Vectors must be given in the form 'ai+bj+ck' in this context"); } -############################################## -############################################## - package LimitedVector; sub Init { - # + # Build the new context that calls the # above classes rather than the usual ones - # my $context = $main::context{LimitedVector} = Parser::Context->getCopy("Vector"); $context->{name} = "LimitedVector"; @@ -232,33 +200,27 @@ sub Init { 'u+' => { class => 'LimitedVector::UOP::plus' }, 'u-' => { class => 'LimitedVector::UOP::minus' }, ); - # + # Remove these operators and functions - # + $context->operators->undefine('_', 'U', '><', '.'); $context->functions->undefine('norm', 'unit'); $context->lists->set( AbsoluteValue => { class => 'LimitedVector::List::AbsoluteValue' }, Vector => { class => 'LimitedVector::List::Vector' }, ); - # + # Format can be 'coordinate', 'ijk', or 'either' - # - $context->flags->set(vector_format => 'either'); - ######################### + $context->flags->set(vector_format => 'either'); $context = $main::context{'LimitedVector-ijk'} = $main::context{LimitedVector}->copy; $context->flags->set(vector_format => 'ijk'); - ######################### - $context = $main::context{'LimitedVector-coordinate'} = $main::context{LimitedVector}->copy; $context->flags->set(vector_format => 'coordinate'); $context->constants->undefine('i', 'j', 'k'); - ######################### - main::Context("LimitedVector"); ### FIXME: probably should require author to set this explicitly } diff --git a/macros/contexts/contextMatrixExtras.pl b/macros/contexts/contextMatrixExtras.pl index 6acb3e0f19..4f875e14d2 100644 --- a/macros/contexts/contextMatrixExtras.pl +++ b/macros/contexts/contextMatrixExtras.pl @@ -1,7 +1,8 @@ +# Note: this is in the Matrix MathObject now, deprecate? =head1 NAME -F - Add transpose, trace, and determinant to Matrix context +contextMatrixExtras.pl - Add transpose, trace, and determinant to Matrix context =head1 DESCRIPTION @@ -63,11 +64,9 @@ sub _contextMatrixExtras_init { ); } -#################################################### -# # Implements the ^T operation on matrices # (as a right-associative unary operator) -# + package context::MatrixExtras::UOP::transpose; @ISA = ("Parser::UOP"); @@ -83,34 +82,29 @@ sub perl { return '(' . $self->{op}->perl . '->transpose)'; } -#################################################### -# # Implement functions with one matrix input and real output -# + package context::MatrixExtras::Function::matrix; our @ISA = ("Parser::Function"); -# # Check for a single Matrix-valued input -# + sub _check { (shift)->checkMatrix(@_) } -# # Evaluate by promoting to a Matrix # and then calling the routine from the Value package -# + sub _eval { my $self = shift; my $name = $self->{def}{method} || $self->{name}; $self->Package("Matrix")->promote($self->context, $_[0])->$name; } -# # Check for a single Matrix-valued argument # Then promote it to a Matrix (does error checking) # and call the routine from Value package (after # converting "tr" to "trace") -# + sub _call { my $self = shift; my $name = shift; diff --git a/macros/contexts/contextOrdering.pl b/macros/contexts/contextOrdering.pl index 34b7d9e431..18c9b658d0 100644 --- a/macros/contexts/contextOrdering.pl +++ b/macros/contexts/contextOrdering.pl @@ -81,18 +81,14 @@ =head1 DESCRIPTION sub _contextOrdering_init { context::Ordering::Init() } -########################################### -# # The main Ordering routines -# package context::Ordering; -# # Here we set up the prototype contexts and define the needed # functions in the main:: namespace. Some error messages are # modified to read better for these contexts. -# + sub Init { my $context = $main::context{Ordering} = Parser::Context->getCopy("Numeric"); $context->{name} = "Ordering"; @@ -127,11 +123,10 @@ sub Init { main::PG_restricted_eval('sub Ordering {context::Ordering::Ordering(@_)}'); } -# # A routine to set the letters allowed in this context. # (Old letters are cleared, and > and = are allowed, but hidden, # since they are used in the List() objects that implement the context). -# + sub Letters { my $context = (Value::isContext($_[0]) ? shift : main::Context()); my @strings; @@ -140,12 +135,11 @@ sub Letters { $context->strings->add('=' => { hidden => 1 }, '>' => { hidden => 1 }); } -# # Create orderings from strings or lists of letter => value pairs. # A copy of the current context is created that contains the proper # letters, and the correct string is created and parsed into an # Ordering object. -# + sub Ordering { my $context = main::Context()->copy; my $string; @@ -176,15 +170,12 @@ sub Ordering { return main::Formula($context, $string)->eval; } -############################################################# -# # This is a Parser BOP used to create the Ordering objects # used internally. They are actually lists with the operator # and the two operands, and the comparisons is based on the # standard list comparisons. The operands are either the strings # for individual letters, or another Ordering object as a # nested List. -# package context::Ordering::BOP::ordering; our @ISA = ('Parser::BOP'); @@ -229,8 +220,6 @@ sub TeX { return $self->{lop}->TeX . " " . $self->{bop} . " " . $self->{rop}->TeX; } -############################################################# -# # This is the Value object used to implement the list That represents # one ordering operation. It is simply a normal Value::List with the # operator as the first entry and the two operands as the remaing @@ -240,14 +229,12 @@ sub TeX { # operators. The cmp_equal method is overriden to make sure the that # the lists are treated as a unit during answer checking. There is # also a routine for adding letters to the object's context. -# package context::Ordering::Value::Ordering; our @ISA = ('Value::List'); -# # Put all equal letters into one list and sort them -# + sub new { my $self = shift; my $context = (Value::isContext($_[0]) ? shift : $self->context); @@ -277,11 +264,10 @@ sub TeX { return join(" $bop ", @rest); } -# # Make sure we do comparison as a list of lists (rather than as the # individual entries in the underlying Value::List that encodes # the ordering) -# + sub cmp_equal { my $self = shift; my $ans = $_[0]; @@ -308,10 +294,9 @@ sub cmp_postprocess { scalar(keys %{ $ans->{student_formula}{tree}{letters} }); } -# # Add more letters to the ordering's context (so student answers # can include them even if they aren't in the correct answer). -# + sub AddLetters { my $self = shift; my $context = $self->context; @@ -323,28 +308,21 @@ sub AddLetters { $context->strings->add(@strings) if scalar(@strings); } -############################################################# -# # This overrides the TeX method of the letters # so that they don't print using the \rm font. -# package context::Ordering::Value::String; our @ISA = ('Value::String'); sub TeX { shift->value } -############################################################# -# # Override Parser classes so that we can check for repeated letters -# package context::Ordering::Parser::String; our @ISA = ('Parser::String'); -# # Save the letters positional reference -# + sub new { my $self = shift; $self = $self->SUPER::new(@_); @@ -352,14 +330,11 @@ sub new { return $self; } -######################### - package context::Ordering::Parser::Value; our @ISA = ('Parser::Value'); -# # Move letters to Value object -# + sub new { my $self = shift; $self = $self->SUPER::new(@_); @@ -367,23 +342,19 @@ sub new { return $self; } -# # Return Ordering class if the object is one -# + sub class { my $self = shift; return "Ordering" if $self->{value}->classMatch('Ordering'); return $self->SUPER::class; } -############################################################# -# # This overrides the cmp_equal method to make sure that # Ordering lists are put into nested lists (since the # underlying ordering is a list, we don't want the # list checker to test the individual parts of the list, # but rather the list as a whole). -# package context::Ordering::Value::List; our @ISA = ('Value::List'); @@ -396,6 +367,4 @@ sub cmp_equal { return $self->SUPER::cmp_equal(@_); } -############################################################# - 1; diff --git a/macros/contexts/contextPartition.pl b/macros/contexts/contextPartition.pl index 77c3f205b5..504999eecd 100644 --- a/macros/contexts/contextPartition.pl +++ b/macros/contexts/contextPartition.pl @@ -1,7 +1,7 @@ =head1 NAME -C - Provides a context that allows the +contextPartition.pl - Provides a context that allows the entry of a partition of an integer as a sum of positive integers. @@ -14,7 +14,7 @@ =head1 DESCRIPTION are equal. -=head1 USAGE +=head1 SYNOPSIS loadMacros("contextPartition.pl"); @@ -34,10 +34,7 @@ =head1 USAGE =cut -########################################################### -# # Create the contexts and add the constructor functions -# sub _contextPartition_init { my $context = $main::context{Partition} = Parser::Context->getCopy("Numeric"); @@ -62,16 +59,13 @@ sub _contextPartition_init { PG_restricted_eval("sub Partition {context::Partition->new(\@_)}"); } -########################################################### -# # The Partition object -# + package context::Partition; our @ISA = ("Value"); -# # Check the data and create the object -# + sub new { my $self = shift; my $class = ref($self) || $self; @@ -90,17 +84,15 @@ sub new { return bless { data => $p, context => $context }, $class; } -# # Add a number to a partition, or add two partitions -# + sub add { my ($self, $l, $r, $other) = Value::checkOpOrderWithPromote(@_); $self->make(@{ $self->{data} }, @{ $other->{data} }); } -# # Produce the sum for a partition -# + sub sum { my $self = shift; my $n = 0; @@ -108,26 +100,23 @@ sub sum { return $n; } -# # Compare two partitions (numbers are promoted) -# + sub compare { my ($self, $l, $r, $other) = Value::checkOpOrderWithPromote(@_); return $l->canonical cmp $r->canonical; } -# # Produce a canonical representation (numbers sorted) -# + sub canonical { my $self = shift; $self->make(main::num_sort(@{ $self->{data} })); } -# # Promote a number to a Real (since we can add a number to a # partition), and promote others to partitions, if possible. -# + sub promote { my $self = shift; my $other = shift; @@ -136,9 +125,8 @@ sub promote { $self->SUPER::promote($other); } -# # Check if types are compatible -# + sub typeMatch { my ($self, $other) = @_; return @@ -147,34 +135,29 @@ sub typeMatch { || ref($other) eq 'ARRAY'; } -# # Produce a string version -# + sub string { my $self = shift; join(" + ", @{ $self->{data} }); } -# # Produce a TeX version -# + sub TeX { my $self = shift; join(" + ", @{ $self->{data} }); } -########################################################### -# # Implement special + operator that produces # partitions rather than sums -# + package context::Partition::BOP::add; our @ISA = ("Parser::BOP"); -# # Check that the operands are appropriate, and return # the proper type reference, or give an error. -# + sub _check { my $self = shift; my ($ltype, $rtype) = ($self->{lop}->typeRef, $self->{rop}->typeRef); @@ -183,20 +166,18 @@ sub _check { $self->{type} = Value::Type("Partition", $ltype->{length} + $rtype->{length}, $Value::Type{number}); } -# # Check that the type of an operand is OK # (It must be a partiation or a number) -# + sub checkOp { my $self = shift; my $op = shift; return $op->{name} eq "Partition" || ($op->{name} eq "Number" && $op->{length} == 1); } -# # Evaluate two numbers by forming a partition, # otherwise use addition (Value object will take over) -# + sub _eval { my $self = shift; my ($a, $b) = @_; @@ -204,7 +185,5 @@ sub _eval { return $a + $b; } -########################################################### - 1; diff --git a/macros/contexts/contextPercent.pl b/macros/contexts/contextPercent.pl index 61cef46fbc..293d7e3bb8 100644 --- a/macros/contexts/contextPercent.pl +++ b/macros/contexts/contextPercent.pl @@ -1,7 +1,7 @@ =head1 NAME -F - Context for entering percentages using C<%> +contextPercent.pl - Context for entering percentages using C<%> =head1 DESCRIPTION @@ -186,10 +186,9 @@ =head1 DESCRIPTION package Percent; -# # Initialization sets up a Perent() constructor and # creates the percent contexts. -# + sub Init { my $context = $main::context{Percent} = Parser::Context->getCopy("Numeric"); $context->{name} = "Percent"; @@ -261,11 +260,8 @@ sub Init { main::PG_restricted_eval('sub Percent {Value->Package("Percent")->new(@_)}'); } -###################################################################### -###################################################################### -# # When creating Number objects in the Parser, keep Percent objects. -# + package Percent::Number; our @ISA = ('Parser::Number'); @@ -275,10 +271,10 @@ sub new { my $value = shift; my $context = $equation->{context}; if (Value::classMatch($value, "Percent")) { - # + # Put it back into a Value object, but must unmark it # as a Real temporarily to avoid an infinite loop. - # + $value->{isReal} = 0; $value = $self->Item("Value")->new($equation, [$value]); $value->{value}{isReal} = 1; @@ -288,13 +284,11 @@ sub new { return $value; } -################################################## -# # This class implements the percent symbol. # It checks that its operand is a numeric constant # in the correct format, and produces # a Percent object when evaluated. -# + package Percent::UOP::percent; our @ISA = ('Parser::UOP'); @@ -325,30 +319,25 @@ sub _eval { Value->Package("Percent")->make($self->context, $value, @_); } -# # Use the Percent MathObject to produce the output formats -# + sub string { (shift)->eval->string } sub TeX { (shift)->eval->TeX } sub perl { (shift)->eval->perl } -###################################################################### -###################################################################### -# # This is the MathObject class for Percent objects. # It is basically a Real(), but one that stringifies # and texifies itself to include the percent symbol, # and evaluates to its value divided by 100. -# + package Percent::Percent; our @ISA = ('Value::Real'); -# # We need to override the new() and make() methods # so that the Percent object will be counted as # a Value object. If we aren't promoting Reals, # produce an error message. -# + sub new { my $self = shift; my $class = ref($self) || $self; @@ -385,9 +374,8 @@ sub truncate { return $self->make(($n + 0) / 100); } -# # Format the output as a percent value. -# + sub format { my $self = shift; my $type = shift; @@ -401,14 +389,12 @@ sub format { sub string { (shift)->format("string") } sub TeX { (shift)->format("TeX") } -# # Override the class name to get better error messages -# + sub cmp_class {"a Percentage Value"} -# # Check for whether we want to work with reals as percents -# + sub typeMatch { my $self = shift; my $other = shift; @@ -417,22 +403,15 @@ sub typeMatch { return Value::classMatch($other, 'Percent'); } -###################################################################### -###################################################################### -# # LimitedPercent contexts -# -################################################## -# # Handle common checking for BOPs -# + package LimitedPercent::BOP; -# # Do original check and then if the operands are numbers, its OK. # Otherwise report an error. -# + sub _check { my $self = shift; my $super = ref($self); @@ -443,42 +422,27 @@ sub _check { $self->Error("In this context, '%s' can only be used with Numbers", $bop); } -############################################## -# # Now we get the individual replacements for the operators # that we don't want to allow. We inherit everything from # the original Parser::BOP class, except the _check # routine, which comes from LimitedPercent::BOP above. -# package LimitedPercent::BOP::add; our @ISA = qw(LimitedPercent::BOP Parser::BOP::add); -############################################## - package LimitedPercent::BOP::subtract; our @ISA = qw(LimitedPercent::BOP Parser::BOP::subtract); -############################################## - package LimitedPercent::BOP::multiply; our @ISA = qw(LimitedPercent::BOP Parser::BOP::multiply); -############################################## - package LimitedPercent::BOP::divide; our @ISA = qw(LimitedPercent::BOP Parser::BOP::divide); -############################################## - package LimitedPercent::BOP::power; our @ISA = qw(LimitedPercent::BOP Parser::BOP::power); -############################################## -############################################## -# # Now we do the same for the unary operators -# package LimitedPercent::UOP; @@ -492,22 +456,13 @@ sub _check { $self->Error("In this context, '%s' can only be used with Numbers", $uop); } -############################################## - package LimitedPercent::UOP::plus; our @ISA = qw(LimitedPercent::UOP Parser::UOP::plus); -############################################## - package LimitedPercent::UOP::minus; our @ISA = qw(LimitedPercent::UOP Parser::UOP::minus); -############################################## -############################################## -# -# Absolute value does vector norm, so we -# trap that as well. -# +# Absolute value does vector norm, so we trap that as well. package LimitedPercent::List::AbsoluteValue; our @ISA = qw(Parser::List::AbsoluteValue); @@ -519,9 +474,4 @@ sub _check { $self->Error("In this context, absolute values can only be used with Numbers"); } -############################################## -############################################## - -###################################################################### - 1; diff --git a/macros/contexts/contextPermutation.pl b/macros/contexts/contextPermutation.pl index 2b4b290c3e..fbe7c692f3 100644 --- a/macros/contexts/contextPermutation.pl +++ b/macros/contexts/contextPermutation.pl @@ -1,27 +1,12 @@ -=head1 NAME - -C - Provides contexts that allow the -entry of cycles and permutations. - - -=head1 DESCRIPTION +# Note: there are two nearly identical macros. this and contextPermutationUBC. +# We need to select the better one and deprecate/delete the other. -These contexts allow you to enter permutations using cycle notation. -The entries in a cycle are separated by spaces and enclosed in -parentheses. Cycles are multiplied by juxtaposition. A permutation -can be multiplied on the left by a number in order to obtain the -result of that number under the action of the permutation. -Exponentiation is also allowed (as described below). - -There are three contexts included here: C, which -allows permutations in any form, C, which -only allows permutations that use disjoint cycles, and -C, which only allows permutations that -are written in canonical form (as described below). +=head1 NAME +contextPermutation - Provides contexts that allow the entry of cycles and permutations. -=head1 USAGE +=head1 SYNOPSIS loadMacros("contextPermutation.pl"); @@ -48,6 +33,21 @@ =head1 USAGE $P2 = Compute("(5 4)(3 1 2)"); $P1 == $P2; # is true +=head1 DESCRIPTION + +These contexts allow you to enter permutations using cycle notation. +The entries in a cycle are separated by spaces and enclosed in +parentheses. Cycles are multiplied by juxtaposition. A permutation +can be multiplied on the left by a number in order to obtain the +result of that number under the action of the permutation. +Exponentiation is also allowed (as described below). + +There are three contexts included here: C, which +allows permutations in any form, C, which +only allows permutations that use disjoint cycles, and +C, which only allows permutations that +are written in canonical form (as described below). + Cycles and permutations can be multiplied to obtain the permutation that consists of one followed by the other, or multiplied on the left by a number to obtain the image of the number under the permutation. diff --git a/macros/contexts/contextPermutationUBC.pl b/macros/contexts/contextPermutationUBC.pl index 18ff77a1c5..09380b8451 100644 --- a/macros/contexts/contextPermutationUBC.pl +++ b/macros/contexts/contextPermutationUBC.pl @@ -1,10 +1,11 @@ +# Note: there are two nearly identical macros. this and contextPermutation.pl +# We need to select the better one and deprecate/delete the other. =head1 NAME C - Provides contexts that allow the entry of cycles and permutations. - =head1 DESCRIPTION These contexts allow you to enter permutations using cycle notation. @@ -20,7 +21,6 @@ =head1 DESCRIPTION C, which only allows permutations that are written in canonical form (as described below). - =head1 USAGE loadMacros("contextPermutationUBC.pl"); diff --git a/macros/contexts/contextPiecewiseFunction.pl b/macros/contexts/contextPiecewiseFunction.pl index f30315dc7c..747a9a56d4 100644 --- a/macros/contexts/contextPiecewiseFunction.pl +++ b/macros/contexts/contextPiecewiseFunction.pl @@ -3,20 +3,11 @@ =head1 NAME contextPiecewiseFunction.pl - Allow usage of piecewise functions. -=head1 DESCRIPTION - -This file implements a context in which piecewise-defined functions -can be specified by students and problem authors. To use it, add +=head1 SYNOPSIS loadMacros("contextPiecewiseFunction.pl"); - -and then use - Context("PiecewiseFunction"); -to select the context for piecewise functions. There are several -ways to produce a piecewise function. For example: - $f = Compute("x if x >= 0 else -x"); $f = Compute("x if x >= 0 else -x if x < 0"); $f = Formula("x+1 if x > 2 else 4 if x = 2 else 1-x"); @@ -25,6 +16,11 @@ =head1 DESCRIPTION $f = PiecewiseFunction("(1,2]" => "x^2", "2x+1"); $f = PiecewiseFunction(Interval("(1,2]") => "x^2", "2x+1"); +=head1 DESCRIPTION + +This file implements a context in which piecewise-defined functions +can be specified by students and problem authors. + You can use either Compute() or Formula() interchangeably to convert a string containing "if" and "else" to the corresponding PiecewiseFunction. The PiecewiseFunction() constructor can @@ -47,24 +43,20 @@ =head1 DESCRIPTION $f = Formula("1-x if x > 0 else 4 if x = 0 else 1+x if x < 0"); $a = random(-2,2,.1); - Context()->texStrings; - BEGIN_TEXT - If \[f(x)=$f\] then \(f($a)\) = \{ans_rule(20)\}. - END_TEXT - Context()->normalStrings; - - ANS($f->eval(x=>$a)->cmp); + BEGIN_PGML + If [`f(x)=[$f]`] then [`f($a)`] = [_]{$f->eval(x => $a)} + END_PGML Normally when you use a piecewise function at the end of a sentence, the period is placed at the end of the last case. Since - \[ f(x) = $f \]. + [` f(x) = $f `]. would put the period centered at the right-hand side of the function, this is not what is desired. To get a period at the end of the last case, use - \[ f(x) = \{$f->with(final_period=>1)\} \] + [` f(x) = [@ $f->with(final_period=>1) @] `] instead. diff --git a/macros/contexts/contextPolynomialFactors.pl b/macros/contexts/contextPolynomialFactors.pl index 346d0ea687..99883d2661 100644 --- a/macros/contexts/contextPolynomialFactors.pl +++ b/macros/contexts/contextPolynomialFactors.pl @@ -53,14 +53,10 @@ =head1 DESCRIPTION =cut -################################################## - loadMacros("MathObjects.pl", "contextLimitedPolynomial.pl"); sub _contextPolynomialFactors_init { PolynomialFactors::Init() } -############################################## - package PolynomialFactors::BOP::add; our @ISA = qw(LimitedPolynomial::BOP::add); @@ -72,8 +68,6 @@ sub checkPolynomial { $self->checkPowers; } -############################################## - package PolynomialFactors::BOP::subtract; our @ISA = qw(LimitedPolynomial::BOP::subtract); @@ -85,8 +79,6 @@ sub checkPolynomial { $self->checkPowers; } -############################################## - package PolynomialFactors::BOP::multiply; our @ISA = qw(LimitedPolynomial::BOP::multiply); @@ -133,8 +125,6 @@ sub checkStrict { $self->Error("You can only use '%s' between coefficents and variables or between factors", $self->{bop}); } -############################################## - package PolynomialFactors::BOP::divide; our @ISA = qw(LimitedPolynomial::BOP::divide); @@ -161,8 +151,6 @@ sub checkPolynomial { return 1; } -############################################## - package PolynomialFactors::BOP::power; our @ISA = qw(LimitedPolynomial::BOP::power); @@ -196,8 +184,6 @@ sub checkStrict { $self->Error("You can only use powers of a variable or factor"); } -############################################## - package PolynomialFactors::UOP::minus; our @ISA = qw(LimitedPolynomial::UOP::minus); @@ -213,15 +199,11 @@ sub checkPolynomial { return 1; } -############################################## - package PolynomialFactors::Formula; our @ISA = ('Value::Formula'); sub cmp_postprocess { } -############################################## - package PolynomialFactors; our @ISA = ('LimitedPolynomal'); @@ -249,10 +231,9 @@ sub markOpFactor { } sub Init { - # + # Build the new context that calls the # above classes rather than the usual ones - # my $context = $main::context{PolynomialFactors} = Parser::Context->getCopy("LimitedPolynomial"); $context->{name} = "PolynomialFactors"; @@ -275,9 +256,8 @@ sub Init { $context->{value}{'Formula'} = "PolynomialFactors::Formula"; $context->{parser}{'Formula'} = "PolynomialFactors::Formula"; - # # A context where coefficients can't include operations - # + $context = $main::context{"PolynomialFactors-Strict"} = $context->copy; $context->flags->set( strictCoefficients => 1, diff --git a/macros/contexts/contextRationalExponent.pl b/macros/contexts/contextRationalExponent.pl index 78ff4aeb38..684413ad49 100644 --- a/macros/contexts/contextRationalExponent.pl +++ b/macros/contexts/contextRationalExponent.pl @@ -1,7 +1,8 @@ =head1 NAME -contextRationalExponent.pl - allows the requirement of simplified rational exponent answers. May be a misnomer since nothing requires exponents to be rational. +contextRationalExponent.pl - allows the requirement of simplified rational exponent answers. +May be a misnomer since nothing requires exponents to be rational. =head1 DESCRIPTION @@ -16,14 +17,10 @@ =head1 DESCRIPTION =cut -loadMacros( - "bizarroArithmetic.pl", +loadMacros("bizarroArithmetic.pl"); -); - -# # Set up the RationalExponent context -# + sub _contextRationalExponent_init { my $context = $main::context{RationalExponent} = Parser::Context->getCopy("Numeric"); Parser::Number::NoDecimals($context); @@ -93,10 +90,7 @@ sub _contextRationalExponent_init { } -########################### -# # Create root(n, x) -# package my::Function::numeric2; our @ISA = ('Parser::Function::numeric2'); @@ -122,16 +116,13 @@ sub TeX { return '\sqrt[' . $n->TeX . "]{" . $x->TeX . "}"; } -########################### -# # Subclass the numeric functions -# + package my::Function::numeric; our @ISA = ('Parser::Function::numeric'); -# # Override sqrt() to return a special value times x when evaluated -# + sub sqrt { my $self = shift; my $x = shift; diff --git a/macros/contexts/contextRationalFunction.pl b/macros/contexts/contextRationalFunction.pl index 27e6073f43..ace59c2d44 100644 --- a/macros/contexts/contextRationalFunction.pl +++ b/macros/contexts/contextRationalFunction.pl @@ -1,8 +1,7 @@ =head1 NAME -contextRationalFunction.pl - Only allow rational functions - (and their products and powers) +contextRationalFunction.pl - Only allow rational functions (and their products and powers) =head1 DESCRIPTION @@ -36,14 +35,10 @@ =head1 DESCRIPTION =cut -################################################## - loadMacros("MathObjects.pl", "contextPolynomialFactors.pl"); sub _contextRationalFunction_init { RationalFunction::Init() } -############################################## - package RationalFunction::BOP::multiply; our @ISA = qw(PolynomialFactors::BOP::multiply); @@ -60,8 +55,6 @@ sub checkFactors { return 1; } -############################################## - package RationalFunction::BOP::divide; our @ISA = qw(PolynomialFactors::BOP::divide); @@ -104,8 +97,6 @@ sub checkFactors { return 1; } -############################################## - package RationalFunction::BOP::power; our @ISA = qw(PolynomialFactors::BOP::power); @@ -117,8 +108,6 @@ sub checkPolynomial { return 1; } -############################################## - package RationalFunction::UOP::minus; our @ISA = qw(PolynomialFactors::UOP::minus); @@ -129,16 +118,13 @@ sub checkPolynomial { return 1; } -############################################## - package RationalFunction; our @ISA = ('PolynomialFactors'); sub Init { - # + # Build the new context that calls the # above classes rather than the usual ones - # my $context = $main::context{RationalFunction} = Parser::Context->getCopy("PolynomialFactors"); $context->{name} = "RationalFunction"; @@ -156,9 +142,8 @@ sub Init { ); $context->flags->set(strictPowers => 1); - # # A context where coefficients can't include operations - # + $context = $main::context{"RationalFunction-Strict"} = $context->copy; $context->flags->set( strictCoefficients => 1, diff --git a/macros/contexts/contextReaction.pl b/macros/contexts/contextReaction.pl index 66a16fa5e8..09fc604bbb 100644 --- a/macros/contexts/contextReaction.pl +++ b/macros/contexts/contextReaction.pl @@ -62,7 +62,7 @@ =head1 DESCRIPTION $products = Formula("4CO_2 + 6H_2O"); BEGIN_PGML - [`[$reactants] \longrightarrow`] [_____________________]{$products}. + [`[$reactants] \longrightarrow`] [_]{$products}{25}. END_PGML Note that sums are simplified during comparisons, so that @@ -110,20 +110,15 @@ =head1 DESCRIPTION =cut -###################################################################### - sub _contextReaction_init { context::Reaction::Init() } -###################################################################### -# # The main MathObject class for reactions -# + package context::Reaction; our @ISA = ('Value::Formula'); -# # Some type declarations for the various classes -# + our $ELEMENT = { isValue => 1, type => Value::Type('Element', 1) }; our $MOLECULE = { isValue => 1, type => Value::Type('Molecule', 1) }; our $ION = { isValue => 1, type => Value::Type('Ion', 1) }; @@ -133,9 +128,8 @@ package context::Reaction; our $CONSTANT = { isValue => 1, type => Value::Type('Constant', 1) }; our $STATE = { isValue => 1, type => Value::Type('State', 1) }; -# # Set up the context and Reaction() constructor -# + sub Init { my $context = $main::context{Reaction} = Parser::Context->getCopy('Numeric'); $context->{name} = 'Reaction'; @@ -273,9 +267,8 @@ sub Init { main::PG_restricted_eval('sub Reaction {Value->Package("Formula")->new(@_)};'); } -# # Handle postfix - and + in superscripts -# + sub Op { my $self = shift; my $name = shift; @@ -301,9 +294,8 @@ sub Op { $self->SUPER::Op($name, $ref); } -# # Handle superscripts of just + or - -# + sub Close { my $self = shift; my $type = shift; @@ -329,9 +321,8 @@ sub SimpleCharge { $self->pushOperand($self->Item('UOP')->new($self, $top->{name}, $one, $self->{ref})); } -# # Compare by checking of the trees are equivalent -# + sub compare { my ($l, $r) = @_; my $self = $l; @@ -340,27 +331,24 @@ sub compare { return ($l->{tree}->equivalent($r->{tree}) ? 0 : 1); } -# # Don't allow evaluation -# + sub eval { my $self = shift; $self->Error("Can't evaluate " . $self->TYPE); } -# # Provide a useful name -# + sub TYPE {'a chemical reaction'} sub cmp_class {'a Chemical Reaction'} -# # Set up the answer checker. Avoid the list checker in # Value::Formula::cmp_equal (for when the answer is a # sum of compounds) and provide a postprocessor to # give warnings when a reaction is compared to a # student answer that isn't a reaction. -# + sub cmp_defaults { (showTypeWarnings => 1) } sub cmp_equal { Value::cmp_equal(@_) } @@ -372,27 +360,23 @@ sub cmp_postprocess { if $ans->{showTypeWarnings} && $ans->{student_value}{tree}->type ne 'Reaction'; } -# # Since the context only allows things that are comparable, we # don't really have to check anything. (But if someone added # strings or constants, we would.) -# + sub typeMatch { my $self = shift; my $other = shift; return 1; } -###################################################################### -# # The replacement for the Parser:Number class -# + package context::Reaction::Number; our @ISA = ('Parser::Number'); -# # Equivalent is equal -# + sub equivalent { my $self = shift; my $other = shift; @@ -405,16 +389,13 @@ sub equivalent { sub class {'Number'} sub TYPE {'a Number'} -###################################################################### -# # The replacement for Parser::Variable. We hold the elements here. -# + package context::Reaction::Variable; our @ISA = ('Parser::Variable'); -# # Two elements are equivalent if their names are equal -# + sub equivalent { my $self = shift; my $other = shift; @@ -427,9 +408,8 @@ sub equivalent { sub isChemical {1} -# # Print element names in Roman -# + sub TeX { my $self = shift; return "{\\rm $self->{name}}"; @@ -437,34 +417,29 @@ sub TeX { sub class {'Variable'} -# # For a printable name, use a constant's name, # and 'an element' for an element. -# + sub TYPE { my $self = shift; return ($self->type eq 'Constant' ? 'a constant' : $self->type eq 'State' ? 'a state' : 'an element'); } -###################################################################### -# # General binary operator (add, multiply, arrow, and underscore # are subclasses of this). -# + package context::Reaction::BOP; our @ISA = ('Parser::BOP'); -# # Binary operators produce chemicals (unless overridden, as in arrow) -# + sub isChemical {1} sub eval { context::Reaction::eval(@_) } -# # Two nodes are equivalent if their operands are equivalent # and they have the same operator -# + sub equivalent { my $self = shift; my $other = shift; @@ -475,21 +450,17 @@ sub equivalent { return $self->{lop}->equivalent($other->{lop}) && $self->{rop}->equivalent($other->{rop}); } -###################################################################### -# # Implements the --> operator -# + package context::Reaction::BOP::arrow; our @ISA = ('context::Reaction::BOP'); -# # It is a reaction, not a chemical -# + sub isChemical {0} -# # Check that the operands are correct. -# + sub _check { my $self = shift; $self->Error("The left-hand side of '-->' must be a (sum of) reactants, not %s", $self->{lop}->TYPE) @@ -501,17 +472,14 @@ sub _check { sub TYPE {'a reaction'} -###################################################################### -# # Implements addition, which forms a list of operands, so acts like # the Parser::BOP::comma operator -# + package context::Reaction::BOP::add; our @ISA = ('Parser::BOP::comma', 'context::Reaction::BOP'); -# # Check that the operands are OK -# + sub _check { my $self = shift; $self->Error("Can't add %s and %s", $self->{lop}->TYPE, $self->{rop}->TYPE) @@ -519,11 +487,10 @@ sub _check { $self->SUPER::_check(@_); } -# # Two are equivalent if they are equivalent in either order. # (never really gets used, since these result in the creation # of a list rather than an "add" node in the final tree. -# + sub equivalent { my $self = shift; my $other = shift; @@ -534,17 +501,14 @@ sub equivalent { sub TYPE {'a sum of Compounds'} -###################################################################### -# # Implements concatenation, which produces compounds or integer # multiples of elements or molecules. -# + package context::Reaction::BOP::multiply; our @ISA = ('context::Reaction::BOP'); -# # Check that the operands are OK -# + sub _check { my $self = shift; my ($lop, $rop) = ($self->{lop}, $self->{rop}); @@ -570,9 +534,8 @@ sub _check { $self->{hasNumber} = 1 if $self->{lop}->class eq 'Number'; } -# # Remove ground state, if needed -# + sub equivalent { my $self = shift; my $other = shift; @@ -586,9 +549,8 @@ sub equivalent { return ($equiv || !$self->{hasState} || $states ? $equiv : $self->{lop}->equivalent($other)); } -# # No space in output for implied multiplication -# + sub string { my $self = shift; return $self->{lop}->string . $self->{rop}->string; @@ -599,24 +561,20 @@ sub TeX { return $self->{lop}->TeX . $self->{rop}->TeX; } -# # Handle states separately -# + sub TYPE { my $self = shift; return $self->{rop}->TYPE eq 'a state' ? $self->{lop}->TYPE . ' with state' : 'a compound'; } -###################################################################### -# # Implements the underscore for creating molecules -# + package context::Reaction::BOP::underscore; our @ISA = ('context::Reaction::BOP'); -# # Check that the operands are OK -# + sub _check { my $self = shift; my ($lop, $rop) = ($self->{lop}, $self->{rop}); @@ -627,9 +585,8 @@ sub _check { $self->{type} = $MOLECULE->{type}; } -# # Create proper TeX output -# + sub TeX { my $self = shift; my $left = $self->{lop}->TeX; @@ -637,9 +594,8 @@ sub TeX { return $left . '_{' . $self->{rop}->TeX . '}'; } -# # Create proper text output -# + sub string { my $self = shift; my $left = $self->{lop}->string; @@ -649,16 +605,13 @@ sub string { sub TYPE {'a molecule'} -###################################################################### -# # Implements the superscript for creating ions -# + package context::Reaction::BOP::superscript; our @ISA = ('context::Reaction::BOP'); -# # Check that the operands are OK -# + sub _check { my $self = shift; my ($lop, $rop) = ($self->{lop}, $self->{rop}); @@ -669,9 +622,8 @@ sub _check { $self->{type} = $ION->{type}; } -# # Create proper TeX output -# + sub TeX { my $self = shift; my $left = $self->{lop}->TeX; @@ -679,9 +631,8 @@ sub TeX { return $left . '^{' . $self->{rop}->TeX . '}'; } -# # Create proper text output -# + sub string { my $self = shift; my $left = $self->{lop}->string; @@ -693,10 +644,8 @@ sub string { sub TYPE {'an ion'} -###################################################################### -# # General unary operator (minus and plus are subclasses of this). -# + package context::Reaction::UOP; our @ISA = ('Parser::UOP'); @@ -709,17 +658,15 @@ sub _check { $self->Error("Can't use unary '%s' with %s", $name, $self->{op}->TYPE); } -# # Unary operators produce numbers -# + sub isChemical {0} sub eval { context::Reaction::eval(@_) } -# # Two nodes are equivalent if their operands are equivalent # and they have the same operator -# + sub equivalent { my $self = shift; my $other = shift; @@ -731,18 +678,16 @@ sub equivalent { return $self->{op}->equivalent($other->{op}); } -# # Always put signs on the right -# + sub string { my $self = shift; my $n = $self->{op}->string($uop->{precedence}); return ($n eq '1' ? '' : $n) . $self->{def}{string}; } -# # Always put signs on the right -# + sub TeX { my $self = shift; my $uop = $self->{def}; @@ -752,30 +697,23 @@ sub TeX { sub TYPE {'a charge'} -###################################################################### -# # Negative numbers (for ion exponents) -# + package context::Reaction::UOP::minus; our @ISA = ('context::Reaction::UOP'); -###################################################################### -# # Positive numbers (for ion exponents) -# + package context::Reaction::UOP::plus; our @ISA = ('context::Reaction::UOP'); -###################################################################### -# # Implements sums of compounds as a list -# + package context::Reaction::List::List; our @ISA = ('Parser::List::List'); -# # Two sums are equivalent if their terms agree in any order. -# + sub equivalent { my ($self, $other) = @_; $other = $self->new($self->{equation}, [$other], 1, $self->context->parens->get('('), $other->type) @@ -803,12 +741,11 @@ sub equivalent { return 1; } -# # Get a hash of element (or compound, etc.) names used in the list # mapping to the count of each and a hash of the states used and # their counts. States are only recorded if students don't need # to include them (otherwise the hash names will include the states). -# + sub organizeList() { my $self = shift; my $required = $self->context->flags->get('studentsMustUseStates'); @@ -830,9 +767,8 @@ () return $list; } -# # Use "+" between entries in the list (with no parens) -# + sub TeX { my $self = shift; my $precedence = shift; @@ -847,10 +783,8 @@ sub TeX { sub TYPE {'a sum of compounds'} -###################################################################### -# # Implements complexes as a list -# + package context::Reaction::List::Complex; our @ISA = ('Parser::List::List'); @@ -864,10 +798,9 @@ sub _check { $self->{type} = $COMPLEX->{type}; } -# # Two complexes are equivalent if their contents are equivalent # (we check by stringifying them and sorting, then compare results) -# + sub equivalent { my $self = shift; my $other = shift; @@ -881,6 +814,4 @@ sub equivalent { sub TYPE {'a complex'} -###################################################################### - 1; diff --git a/macros/contexts/contextRestrictedDomains.pl b/macros/contexts/contextRestrictedDomains.pl index e09dc94d76..48b7918236 100644 --- a/macros/contexts/contextRestrictedDomains.pl +++ b/macros/contexts/contextRestrictedDomains.pl @@ -1,10 +1,12 @@ =head1 NAME -Describe this context here. +contextRestrictedDomains.pl - provide a way for students to enter formulas with a restricted domain. =head1 DESCRIPTION + + =cut loadMacros("MathObjects.pl", "bizarroArithmetic.pl", "contextInequalitySetBuilder.pl", "PGinfo.pl",); @@ -20,7 +22,9 @@ sub _contextRestrictedDomains_init { checkRoot => 0, setSqrt => exp(1) / main::ln(2), wrongFormMessage => - 'Your answer is algebraically equivalent to the correct answer, but not in the expected form. Maybe it is not fully simplified. Maybe something is not completely factored. Maybe it is not in the expected form for some other reason.', + 'Your answer is algebraically equivalent to the correct answer, but not in the expected form. ' + . 'Maybe it is not fully simplified. Maybe something is not completely factored. ' + . 'Maybe it is not in the expected form for some other reason.', useBizarro => 1, expressionWeight => 0.9, ); @@ -180,16 +184,13 @@ sub _contextRestrictedDomains_init { }; } -########################### -# # Subclass the numeric functions -# + package restrictedDomains::Function::numeric; our @ISA = ('Parser::Function::numeric'); -# # Override sqrt() to return a special value times x when evaluated -# + sub sqrt { my $self = shift; my $x = shift; diff --git a/macros/contexts/contextScientificNotation.pl b/macros/contexts/contextScientificNotation.pl index 1a946bfa0b..8b35fd71c8 100644 --- a/macros/contexts/contextScientificNotation.pl +++ b/macros/contexts/contextScientificNotation.pl @@ -97,24 +97,21 @@ =head1 DESCRIPTION package ScientificNotation; -# # Creates and initializes the ScientificNotation context -# + sub Init { - # + # Create the Scientific Notation context - # + my $context = $main::context{ScientificNotation} = Parser::Context->getCopy("Numeric"); $context->{name} = "ScientificNotation"; - # # Make numbers include the leading + or - and not allow E notation - # + $context->{pattern}{number} = '[-+]?(?:\d+(?:\.\d*)?|\.\d+)'; - # # Remove all the stuff we don't need - # + $context->variables->clear; $context->constants->clear; $context->parens->clear; @@ -122,9 +119,8 @@ sub Init { $context->functions->clear; $context->strings->clear; - # # Only allow x and ^ operators - # + $context->operators->add( 'x' => { precedence => 3, @@ -155,13 +151,12 @@ sub Init { } ); - # # Don't reduce constant values (so 10^2 won't be replaced by 100) - # + $context->flags->set(reduceConstants => 0); - # + # Flags controlling input and output - # + $context->flags->set( snDigits => 6, # number of decimal digits in mantissa for output snTrimZeros => 1, # 1 means remove trailing 0's, 0 means leave them @@ -171,36 +166,30 @@ sub Init { # (negative means no limit) ); - # # Better error message for this case - # + $context->{error}{msg}{"Unexpected character '%s'"} = "'%s' is not allowed in scientific notation"; - # # Hook into the Value package lookup mechanism - # + $context->{value}{ScientificNotation} = 'ScientificNotation::Real'; $context->{value}{"Real()"} = 'ScientificNotation::Real'; - # # Create the constructor function - # + main::PG_restricted_eval('sub ScientificNotation {Value->Package("ScientificNotation")->new(@_)}'); } -################################################## -# # The Scientific Notation multiplication operator -# + package ScientificNotation::BOP::x; our @ISA = qw(Parser::BOP); -# # Check that the operand types are compatible, and give # approrpiate error messages if not. (We have to work # hard to make a good message about the number of # decimal digits required.) -# + sub _check { my $self = shift; my ($lop, $rop) = ($self->{lop}, $self->{rop}); @@ -227,34 +216,29 @@ sub _check { $self->{isScientificNotation} = 1; # mark it so we can tell later on } -# # Perform the multiplication and return a ScientificNotation object -# + sub _eval { my ($self, $a, $b) = @_; $self->Package("ScientificNotation")->make($self->context, $a * $b); } -# # Use the ScientificNotation MathObject to produce the output formats # (if other operators are added back into the context, these will # need to be modified to include parens at the appropriate times) -# + sub string { (shift)->eval->string } sub TeX { (shift)->eval->TeX } sub perl { (shift)->eval->perl } -################################################## -# # Scientific Notation exponentiation operator -# + package ScientificNotation::BOP::power; our @ISA = qw(Parser::BOP::power); # inherit from standard power (TeX method in particular) -# # Check that the operand types are compatible and # produce appropriate errors if not -# + sub _check { my $self = shift; my ($lop, $rop) = ($self->{lop}, $self->{rop}); @@ -268,16 +252,13 @@ sub _check { $self->{isPowerOf10} = 1; # mark it so BOP::x above can recognize it } -##################################### -# # A subclass of Real that handles scientific notation -# + package ScientificNotation::Real; our @ISA = ("Value::Real"); -# # Override these so we can mark ourselves as scientific notation -# + sub new { my $self = (shift)->SUPER::new(@_); $self->{isValue} = $self->{isScientificNotation} = 1; @@ -290,11 +271,10 @@ sub make { return $self; } -# # Stringify using x notation not E, # using the right number of digits, and trimming # if requested. -# + sub string { my $self = shift; my $digits = $self->getFlag("snDigits"); @@ -304,9 +284,8 @@ sub string { return $r; } -# # Convert x notation to TeX form -# + sub TeX { my $r = (shift)->string; $r =~ s/x/\\times /; @@ -314,14 +293,12 @@ sub TeX { return $r; } -# # What to call us in error messages -# + sub cmp_class {"Scientific Notation"} -# # Only match against strings and Scientific Notation -# + sub typeMatch { my $self = shift; my $other = shift; @@ -329,6 +306,4 @@ sub typeMatch { return $other->{isScientificNotation}; } -######################################################################### - 1; diff --git a/macros/contexts/contextString.pl b/macros/contexts/contextString.pl index 7ee606d2ad..a2a7ff954b 100644 --- a/macros/contexts/contextString.pl +++ b/macros/contexts/contextString.pl @@ -23,8 +23,6 @@ =head1 DESCRIPTION sub _contextString_init { context::String::Init() }; # don't load it again -################################################## - package context::String::Variable; sub new { @@ -36,8 +34,6 @@ sub new { $equation->Error([ "Your answer should be one of %s", $strings ]); } -################################################## - package context::String::Formula; our @ISA = qw(Value::Formula); @@ -58,8 +54,6 @@ sub _check { context::String::Variable->new($self->{equation}); # report an error } -################################################## - package context::String; sub Init { diff --git a/macros/contexts/contextTrigDegrees.pl b/macros/contexts/contextTrigDegrees.pl index 43138d7a75..5b97c8a8d8 100644 --- a/macros/contexts/contextTrigDegrees.pl +++ b/macros/contexts/contextTrigDegrees.pl @@ -14,7 +14,7 @@ =head1 DESCRIPTION in radians. Problems which evaluate trigonometric functions in degrees should alert the student in their text. -=head1 USAGE +=head1 SYNOPSIS Context("TrigDegrees") @@ -22,28 +22,19 @@ =head1 USAGE $b = Compute("cos($a)"); ANS($b->cmp); -=head1 AUTHORS - -Davide Cervone (Union College, Schenectady, New York, USA) - -Paul Pearson (Hope College, Holland, Michigan, USA) - =cut loadMacros('MathObjects.pl'); sub _contextTrigDegrees_init { context::TrigDegrees::Init() }; # don't reload this file -####################################### - package context::TrigDegrees::common; our $deg = $main::PI / 180; -# # Check the number of arguments, and call the proper method with the # the proper factor involved. -# + sub _call { my $self = shift; my $name = shift; @@ -61,9 +52,8 @@ sub _call { } } -# # Call the proper method with the correct factor -# + sub _eval { my $self = shift; my $name = $self->{name}; @@ -75,9 +65,8 @@ sub _eval { } } -# # Do chain rule derivative, taking the $deg factor into account -# + sub D { my $self = shift; my $x = $self->{params}[0]; @@ -94,11 +83,7 @@ sub D { return $self->reduce; } -####################################### - -# # Hook the common functions into these classes -# package context::TrigDegrees::trig; our @ISA = ('context::TrigDegrees::common', 'Parser::Function::trig'); @@ -106,8 +91,6 @@ package context::TrigDegrees::trig; package context::TrigDegrees::hyperbolic; our @ISA = ('context::TrigDegrees::common', 'Parser::Function::hyperbolic'); -####################################### - package context::TrigDegrees::numeric2; our @ISA = ('Parser::Function::numeric2'); @@ -115,18 +98,15 @@ package context::TrigDegrees::numeric2; sub atan2 { CORE::atan2($_[1], $_[2]) / $deg } -####################################### - package context::TrigDegrees; -# # Change the classes for the trig functions to be our classes above, # and mark the inverses so that the degrees can be applied in the # proper location. -# + # Define the sin, cos, and atan2 functions so that they will call our # methods even if their arguments are Perl reals. -# + sub Init { my $context = $main::context{TrigDegrees} = Parser::Context->getCopy("Numeric"); $context->{name} = "TrigDegrees"; diff --git a/macros/contexts/contextTypeset.pl b/macros/contexts/contextTypeset.pl index 8991b5290f..d7a75e85e9 100644 --- a/macros/contexts/contextTypeset.pl +++ b/macros/contexts/contextTypeset.pl @@ -1,3 +1,6 @@ +# Note: perhaps deprecate. This appears to be used for typesets math objects, which +# should be done within the MathObject code itself. + loadMacros("Parser.pl"); sub _contextTypeset_init { } diff --git a/macros/contexts/legacyFraction.pl b/macros/contexts/legacyFraction.pl index dbdcbfe64f..e64f706b75 100644 --- a/macros/contexts/legacyFraction.pl +++ b/macros/contexts/legacyFraction.pl @@ -1,4 +1,7 @@ +# Note: should we strip the POD from this, since it is duplicated in the contextFraction.pl +# macro? + =head1 NAME contextFraction.pl - Implements a MathObject class for Fractions. diff --git a/macros/core/PGML.pl b/macros/core/PGML.pl index bb90e389fd..a86547281d 100644 --- a/macros/core/PGML.pl +++ b/macros/core/PGML.pl @@ -1,5 +1,12 @@ -###################################################################### -###################################################################### + +=head1 NAME + +PGML.pl - Provides the functional for PGML (PG markup language). + +=head1 DESCRIPTION + + +=cut package PGML; @@ -33,8 +40,6 @@ sub isRegexp { return $ref && ref($ref) =~ m/Regexp$/; } -###################################################################### - package PGML::Parse; my $wordStart = qr/[^a-z0-9]/; @@ -589,8 +594,6 @@ sub NOOP { $self->Text("", 1); } -###################################################################### - my $balanceAll = qr/[\{\[\'\"]/; %BlockDefs = ( @@ -774,8 +777,6 @@ sub NOOP { "list" => { type => 'list', parseAll => 1, combine => { list => "bullet", par => 1 }, noIndent => -1 }, ); -###################################################################### - sub terminateGetString { my $self = shift; my $token = shift; @@ -953,9 +954,6 @@ sub replaceCommand { return $result; } -###################################################################### -###################################################################### - package PGML::Item; sub new { @@ -1007,8 +1005,6 @@ sub quote { return $string; } -###################################################################### - package PGML::Block; our @ISA = ('PGML::Item'); @@ -1093,9 +1089,9 @@ sub combineTopItems { ) ) { - # + # Combine identical blocks - # + $prev = $prev->topItem if $inside; splice(@{ $self->{stack} }, $i, 1); if ($par) { splice(@{ $self->{stack} }, $i, 1); $prev->pushItem($par) } @@ -1108,9 +1104,9 @@ sub combineTopItems { && $top->{indent} > $prev->{indent} && $prev->{indent} > 0) { - # + # Move larger indentations into smaller ones - # + splice(@{ $self->{stack} }, $i, 1); if ($par) { splice(@{ $self->{stack} }, $i, 1); $prev->pushItem($par) } $top->{indent} -= $prev->{indent}; @@ -1129,9 +1125,9 @@ sub combineTopItems { } } return; - # + # Remove unneeded zero indents - # + if ($top->{type} eq 'indent' && $top->{indent} == 0) { splice(@{ $self->{stack} }, $i, 1, @{ $top->{stack} }); $top = $self->topItem($i); @@ -1160,8 +1156,6 @@ sub show { return join("\n", @strings); } -###################################################################### - package PGML::Root; our @ISA = ('PGML::Block'); @@ -1194,8 +1188,6 @@ sub pushItem { } } -###################################################################### - package PGML::Block::Table; our @ISA = ('PGML::Block'); @@ -1215,9 +1207,6 @@ sub pushItem { } } -###################################################################### -###################################################################### - package PGML::Text; our @ISA = ('PGML::Item'); @@ -1248,9 +1237,6 @@ sub show { return join("\n", @strings); } -###################################################################### -###################################################################### - package PGML::Format; sub new { @@ -1492,9 +1478,6 @@ sub Image { return (main::image($source, alt => $text, width => $width, height => $height, %$image_options)); } -###################################################################### -###################################################################### - package PGML::Format::html; our @ISA = ('PGML::Format'); @@ -1687,9 +1670,6 @@ sub Tag { return main::tag($tag, @attributes, $self->string($item)); } -###################################################################### -###################################################################### - package PGML::Format::tex; our @ISA = ('PGML::Format'); @@ -1842,9 +1822,6 @@ sub Tag { return ($tex_begin // '') . $self->string($item) . ($tex_end // ''); } -###################################################################### -###################################################################### - package PGML::Format::ptx; our @ISA = ('PGML::Format'); @@ -1998,9 +1975,6 @@ sub Tag { return $self->string($item); } -###################################################################### -###################################################################### - package PGML; sub Format { @@ -2041,8 +2015,6 @@ sub LaTeX { ); } -###################################################################### - package main; sub _PGML_init { @@ -2053,6 +2025,4 @@ sub _PGML_init { Context($context); } -###################################################################### - 1; diff --git a/macros/core/PGanswermacros.pl b/macros/core/PGanswermacros.pl index dd215608e5..b23604fb9b 100644 --- a/macros/core/PGanswermacros.pl +++ b/macros/core/PGanswermacros.pl @@ -1,3 +1,5 @@ +# Note: I don't believe this is used any longer. Deprecate. + # FIXME TODO: # Document and maybe split out: filters, graders, utilities diff --git a/macros/core/PGauxiliaryFunctions.pl b/macros/core/PGauxiliaryFunctions.pl index 5f0b246799..8210ec7322 100644 --- a/macros/core/PGauxiliaryFunctions.pl +++ b/macros/core/PGauxiliaryFunctions.pl @@ -1,8 +1,7 @@ =head1 NAME -A set of auxiliary functions that are often used in PG problems. - +PGauxialliaryFunctions.pl - A set of auxiliary functions that are often used in PG problems. =head1 DESCRIPTION @@ -29,11 +28,11 @@ =head1 DESCRIPTION # ^uses loadMacros loadMacros("PGcommonFunctions.pl"); -sub _PGauxiliaryFunctions_init { +sub _PGauxiliaryFunctions_init { } -} +=head1 MACROS -=head2 step function +=head2 step Usage: C @@ -51,7 +50,7 @@ sub step { # Heaviside function (1 or x>0) ($x > 0) ? 1 : 0; } -=head2 ceil Function +=head2 ceil Usage: C @@ -69,7 +68,7 @@ sub ceil { -floor(-$x); } -=head2 floor Function +=head2 floor Usage: C @@ -89,7 +88,7 @@ sub floor { $out; } -=head2 max function +=head2 max Usage: C @@ -114,9 +113,9 @@ sub max { } -=head2 min function +=head2 min + -=pod Usage: C @@ -143,7 +142,7 @@ sub min { # round added 6/12/2000 by David Etlinger. Edited by AKP 3-6-03 -=head2 round function +=head2 round Usage: C @@ -162,7 +161,7 @@ sub round { $out; } -=head2 Round function +=head2 Round Usage: C @@ -184,7 +183,7 @@ sub Round { elsif (@_ == 2) { $_[0] > 0 ? Round($_[0] * 10**$_[1]) / 10**$_[1] : Round($_[0] * 10**$_[1]) / 10**$_[1] } } -=head2 lcm function +=head2 lcm Usage: C @@ -208,9 +207,9 @@ sub lcm { return lcm($a * $b / gcf($a, $b), @_); } -=head2 gcf function +=head2 gcf + -=pod Usage: C @@ -241,9 +240,9 @@ sub gcf { return gcf($b, @_); } -=head2 gcd function +=head2 gcd + -=pod C @@ -261,9 +260,7 @@ sub gcd { return gcf(@_); } -=head2 random_coprime function - -=pod +=head2 random_coprime Usage: C @@ -358,7 +355,7 @@ sub random_coprime { } } -=head2 random_pairwise_coprime function +=head2 random_pairwise_coprime Usage: C @@ -416,7 +413,7 @@ sub random_pairwise_coprime { } } -=head2 isPrime function +=head2 isPrime Usage: C @@ -441,7 +438,7 @@ sub isPrime { return 1; } -=head2 reduce function +=head2 reduce Usage: C @@ -471,7 +468,7 @@ sub reduce { @frac; } -=head2 preFormat function +=head2 preFormat Usage: C @@ -542,7 +539,7 @@ sub random_subset { return wantarray ? @out : \@out; } -=head2 repeated function +=head2 repeated Usage: C diff --git a/macros/core/PGbasicmacros.pl b/macros/core/PGbasicmacros.pl index 52c1862733..372cf77d4a 100644 --- a/macros/core/PGbasicmacros.pl +++ b/macros/core/PGbasicmacros.pl @@ -1,7 +1,7 @@ =head1 NAME -PGbasicmacros.pl --- located in the courseScripts directory +PGbasicmacros.pl - set of basic functions and constants for PG problems. =head1 DESCRIPTION diff --git a/macros/core/PGcommonFunctions.pl b/macros/core/PGcommonFunctions.pl index c57ce1cefb..2c5a4f95cc 100644 --- a/macros/core/PGcommonFunctions.pl +++ b/macros/core/PGcommonFunctions.pl @@ -1,31 +1,31 @@ +=head1 NAME + +PGcommonFunctions.pl - common mathematical functions used in PG problems. + =head1 DESCRIPTION -############################################## -# -# Implements functions that are common to -# the new Parser.pm and the old PGauxiliaryFunctions.pl -# +This macro provides common mathematics functions (exponential, log, trig and +combinatoric). =cut sub _PGcommonFunctions_init { } -# # Make these interact nicely with Parser.pm -# + package CommonFunction; =head2 NOTE -# + # Either call Parser (if it has been loaded) or # the functions below. (If it's ever the case # that both the Parser and PGauxiliaryFunctions.pl are # both preloaded, then there will be no need for # this, as you can always use the Parser versions. # We only need this because Parser might not be loaded.) -# + =cut @@ -91,15 +91,12 @@ sub P { return $P; } -# # Back to main package -# + package main; -# # Make main versions call the checker to see # which package-specific version to call -# ParserDefineLog(); diff --git a/macros/core/PGgraders.pl b/macros/core/PGgraders.pl index d29946156c..b84f87b77d 100644 --- a/macros/core/PGgraders.pl +++ b/macros/core/PGgraders.pl @@ -1,9 +1,13 @@ -=head1 PGgraders.pl DESCRIPTION +=head1 NAME -Grader Plug-ins +PGgraders.pl - provides a set of basic graders. -=cut +=head1 DESCRIPTION + +This macro provides some wasy to do partial credit as well as some weighting. + +=head1 FUNCTIONS =head2 full_partial_grader diff --git a/macros/core/Value.pl b/macros/core/Value.pl index d9ba08c664..78d87f3fae 100644 --- a/macros/core/Value.pl +++ b/macros/core/Value.pl @@ -1,11 +1,13 @@ -=head1 DESCRIPTION +=head1 NAME - Declares constructors for MathObjects +Value.pl - Declares constructors for MathObjects -=cut +=head1 DESCRIPTION -=head2 Constructors for the various Mathobject types +Declares constructors for MathObjects + +=head2 DESCRIPTION MathObjects are objects which behave much like you would expect their true mathematical counterparts to behave. @@ -73,10 +75,10 @@ =head2 Constructors for the various Mathobject types =head3 Closed($point) - # + # Make a point or list a closed interval. # (Obsolete: use $x->with(open=>'[',close=>']') instead.) - # + =cut @@ -88,8 +90,8 @@ sub Closed { =head3 NOTE: - ########################################################################### - # + + # Make it possible to use 1+3*i in perl rather than 1+3*$i or 1+3*i() # as well as 3*pi instead of 3*pi() @@ -101,6 +103,4 @@ =head3 NOTE: sub _Value_init { }; # don't let loadMacros load it again -########################################################################### - 1; diff --git a/macros/core/externalData.pl b/macros/core/externalData.pl index 8e49a4f263..558be9ffc2 100644 --- a/macros/core/externalData.pl +++ b/macros/core/externalData.pl @@ -1,13 +1,15 @@ =head1 NAME -C - Macro that provides some parsing and way to send data from +externalData.pl - Macro that provides some parsing and way to send data from a problem to the database. This is useful for using data common to multiple problems. =cut sub _externalData_init { } +=head1 MACROS + =head2 store_number_list This is a answer checker that checks only that there are a list of real number values diff --git a/macros/core/sage.pl b/macros/core/sage.pl index 03d12ec473..d0fd17b2ae 100644 --- a/macros/core/sage.pl +++ b/macros/core/sage.pl @@ -1,7 +1,7 @@ =head1 NAME -sage.pl -- connect to a sage server. +sage.pl - connect to a sage server. =cut diff --git a/macros/deprecated/PGcomplexmacros.pl b/macros/deprecated/PGcomplexmacros.pl index 36a069f371..ae45287cc2 100644 --- a/macros/deprecated/PGcomplexmacros.pl +++ b/macros/deprecated/PGcomplexmacros.pl @@ -1,7 +1,8 @@ +# Note: isn't this a MathObject now? Deprecate? =head1 NAME -Macros for complex numbers for the PG language +PGcomplexmacros.pl - Macros for complex numbers for the PG language =cut diff --git a/macros/deprecated/PGcomplexmacros2.pl b/macros/deprecated/PGcomplexmacros2.pl index f11f2032e1..4c4d83512e 100644 --- a/macros/deprecated/PGcomplexmacros2.pl +++ b/macros/deprecated/PGcomplexmacros2.pl @@ -1,10 +1,12 @@ +# Note: is this built-in to the Complex MathObjects? + # This file is PGcomplexmacros2.pl # This includes the subroutines for the ANS macros, that # is, macros allowing a more flexible answer checking =head1 NAME -More macros for handling multivalued functions of a complex variable +PGcomplexmacros2.pl - More macros for handling multivalued functions of a complex variable =cut diff --git a/macros/deprecated/PGsequentialmacros.pl b/macros/deprecated/PGsequentialmacros.pl index a8b08d34f7..e9b2311b96 100644 --- a/macros/deprecated/PGsequentialmacros.pl +++ b/macros/deprecated/PGsequentialmacros.pl @@ -1,12 +1,9 @@ =head1 NAME -PGsequentialmacros.pl - -Provides support for writing sequential problems, where certain parts +PGsequentialmacros.pl - Provides support for writing sequential problems, where certain parts of the problem are hidden until earlier questions are answered correctly. - =head1 SYNPOSIS The basic sequential problem structure: diff --git a/macros/deprecated/weightedGrader.pl b/macros/deprecated/weightedGrader.pl index 24b0ebded0..47a52840c3 100644 --- a/macros/deprecated/weightedGrader.pl +++ b/macros/deprecated/weightedGrader.pl @@ -1,9 +1,7 @@ -sub _weightedGrader_init { }; # don't reload this file - =head1 NAME -weightedGrader.pl +weightedGrader.pl - =head1 DESCRIPTION @@ -156,6 +154,8 @@ =head2 HAVING ONE ANSWER PROVIDE CREDIT FOR ANOTHER: =cut +sub _weightedGrader_init { }; # don't reload this file + ################################################## # # Issue ANS() calls for the weighted checkers diff --git a/macros/graph/LiveGraphicsParametricSurface3D.pl b/macros/graph/LiveGraphicsParametricSurface3D.pl index 6a8c0a7604..95c77eff00 100644 --- a/macros/graph/LiveGraphicsParametricSurface3D.pl +++ b/macros/graph/LiveGraphicsParametricSurface3D.pl @@ -12,7 +12,7 @@ =head1 DESCRIPTION and returns a string of plot data that can be displayed using the C routine of the L macro. -=head1 Methods +=head1 METHODS =head2 ParametricSurface3D diff --git a/macros/graph/PGanalyzeGraph.pl b/macros/graph/PGanalyzeGraph.pl index 561a303a63..9c63cb4a5c 100644 --- a/macros/graph/PGanalyzeGraph.pl +++ b/macros/graph/PGanalyzeGraph.pl @@ -1,12 +1,7 @@ -sub _PGanalyzeGraph_init { } - -################################################################ -# subroutines -################################################################ =head1 NAME -PGanalyzeGraph.pl +PGanalyzeGraph.pl - These routines support the analysis of graphical input from students. =head1 DESCRIPTION @@ -28,6 +23,8 @@ =head2 detect_intervals =cut +sub _PGanalyzeGraph_init { } + sub detect_intervals { my $pointDisplayString = shift; my @intervals; diff --git a/macros/graph/PGgraphgrid.pl b/macros/graph/PGgraphgrid.pl index 524347f713..29fb7ee63b 100644 --- a/macros/graph/PGgraphgrid.pl +++ b/macros/graph/PGgraphgrid.pl @@ -1,10 +1,7 @@ -sub _PGgraphgrid_init { }; # don't reload this file - -=pod =head1 NAME -PGgraphgrid.pl +PGgraphgrid.pl - provides functional for plotting a grid on a graph. =head1 SYNOPSIS @@ -47,7 +44,7 @@ =head1 AUTHORS =cut -################################################ +sub _PGgraphgrid_init { }; # don't reload this file loadMacros("MathObjects.pl", "PGgraphmacros.pl",); diff --git a/macros/graph/PGgraphmacros.pl b/macros/graph/PGgraphmacros.pl index ee2f5e9aa1..6982205556 100644 --- a/macros/graph/PGgraphmacros.pl +++ b/macros/graph/PGgraphmacros.pl @@ -1,7 +1,7 @@ =head1 NAME -PGgraphmacros -- in courseScripts directory +PGgraphmacros.pl - provides functionality for plotting functions, points and adding labels. =head1 SYNPOSIS @@ -21,68 +21,35 @@ =head1 DESCRIPTION may require direct access to the underlying modules. If these complicated projects are common then it may be desirable to create additional macros. (See numericalmacros.pl for one example.) - -=cut - -=head2 Other constructs - See F for definitions of C and C -=cut - -#my $User = $main::studentLogin; -#my $psvn = $main::psvn; #$main::in{'probSetKey'}; #in{'probSetNumber'}; #$main::probSetNumber; -#my $setNumber = $main::setNumber; -#my $probNum = $main::probNum; +=head1 FUNCTIONS -######################################################### -# this initializes a graph object -######################################################### -# graphObject = init_graph(xmin,ymin,xmax,ymax,options) -# options include 'grid' =>[8,8] or -# 'ticks'=>[8,8] and/or -# 'axes' -######################################################### +=head2 init_graph -#loadMacros("MathObjects.pl"); # avoid loading the entire package -# of MathObjects since that can mess up -# problems that don't use MathObjects but use Matrices. -=head2 init_graph + $graphObject = init_graph(xmin,ymin,xmax,ymax,'ticks'=>[4,4],'axes'=>[0,0]) -=pod +options are - $graphObject = init_graph(xmin,ymin,xmax,ymax,'ticks'=>[4,4],'axes'=>[0,0]) - options are - 'grid' =>[8,8] or - # there are 8 evenly spaced lines intersecting the horizontal axis - 'ticks'=>[8,8] and/or - # there are 8 ticks on the horizontal axis, 8 on the vertical - 'axes' => [0,0] - # axes pass through the point (0,0) in real coordinates - 'size' => [200,200] - # dimensions of the graph in pixels. - 'pixels' =>[200,200] # synonym for size + 'grid' =>[8,8] or + # there are 8 evenly spaced lines intersecting the horizontal axis + 'ticks'=>[8,8] and/or + # there are 8 ticks on the horizontal axis, 8 on the vertical + 'axes' => [0,0] + # axes pass through the point (0,0) in real coordinates + 'size' => [200,200] + # dimensions of the graph in pixels. + 'pixels' =>[200,200] # synonym for size Creates a graph object with the default size 200 by 200 pixels. If you want axes or grids you need to specify them in options. But the default values can be selected for you. - =cut BEGIN { strict->import; } -sub _PGgraphmacros_init { - -} -#sub _PGgraphmacros_export { -# -# my @EXPORT = ( -# '&init_graph', '&add_functions', '&plot_functions', '&open_circle', -# '&closed_circle', '&my_math_constants', '&string_to_sub', -# ); -# @EXPORT; -#} +sub _PGgraphmacros_init { } sub init_graph { my ($xmin, $ymin, $xmax, $ymax, %options) = @_; @@ -281,9 +248,7 @@ sub init_graph_no_labels { $graphRef; } -=head2 plot_functions - -=pod +=head2 plot_functions Usage: ($f1, $f2, $f3) = plot_functions($graph, $f1, $f2, $f3); Synonym: add_functions($graph,$f1,$f2,$f3); @@ -397,7 +362,8 @@ =head2 insertGraph TEXT(image(insertGraph($graph)) ); -where C takes care of creating the proper URL for accessing the graph and for creating the HTML code to display the image. +where C takes care of creating the proper URL for accessing the graph and for +creating the HTML code to display the image. Another common usage is: @@ -425,7 +391,6 @@ =head2 'Circle' lables =cut -######################################################### sub open_circle { my ($cx, $cy, $color) = @_; new Circle($cx, $cy, 4, $color, 'nearwhite'); @@ -437,16 +402,15 @@ sub closed_circle { new Circle($cx, $cy, 4, $color, $color); } -=head2 Auxiliary macros - -=head3 string_to_sub and my_math_constants +=head2 tring_to_sub +=head2 my_math_constants These are internal macros which govern the interpretation of equations. +Usage: C<$string = my_math_constants($string)> - Usage: $string = my_math_constants($string) - $subroutine_reference = my_string_to_sub($string) + $subroutine_reference = my_string_to_sub($string) C interprets pi, e as mathematical constants 3.1415926... and 2.71828... respectively. (Case is important). @@ -491,8 +455,8 @@ sub string_to_sub { my ($subRef, $PG_eval_errors, $PG_full_error_report) = PG_restricted_eval(" sub { my \$XVAR = shift; my \$out = $in; \$out; } "); if ($PG_eval_errors) { - die - " ERROR while defining a function from the string:\n\n$main::BR $main::BR $str_in $main::BR $main::BR\n\n $PG_eval_errors"; + die " ERROR while defining a function from the string:\n\n$main::BR $main::BR " + . "$str_in $main::BR $main::BR\n\n $PG_eval_errors"; } else { $out = $subRef; } @@ -501,6 +465,4 @@ sub string_to_sub { $out; } -######################################################### - 1; diff --git a/macros/graph/PGlateximage.pl b/macros/graph/PGlateximage.pl index d4f38a9a75..a8ab0900b3 100644 --- a/macros/graph/PGlateximage.pl +++ b/macros/graph/PGlateximage.pl @@ -27,8 +27,6 @@ =head1 DESCRIPTION image(insertGraph($image)); -=head1 DETAILED USAGE - There are several LaTeXImage parameters that may need to be set for the LaTeXImage object return by createLaTeXImage to generate the desired image. diff --git a/macros/graph/PGnauGraphics.pl b/macros/graph/PGnauGraphics.pl index 728ba25950..5c11f478bf 100644 --- a/macros/graph/PGnauGraphics.pl +++ b/macros/graph/PGnauGraphics.pl @@ -1,4 +1,6 @@ +# Note: this should be deprecated but many problems use it. + sub _PGnauGraphics_init { }; #don't reload this file # loadMacros('PGunion.pl'); loadMacros('PGgraphmacros.pl', 'unionTables.pl', 'PGchoicemacros.pl'); diff --git a/macros/graph/PGstatisticsGraphMacros.pl b/macros/graph/PGstatisticsGraphMacros.pl index b1e95e2c15..a4076c970b 100644 --- a/macros/graph/PGstatisticsGraphMacros.pl +++ b/macros/graph/PGstatisticsGraphMacros.pl @@ -1,8 +1,7 @@ -#require 'PGstatisticsmacros.pl'; =head1 NAME -PGstatisticsGraphMacros -- in courseScripts directory +PGstatisticsGraphMacros.pl - Provides statistic graphs using the WWPlot macros. =head1 SYNPOSIS @@ -24,10 +23,7 @@ =head1 DESCRIPTION common then it may be desirable to create additional macros. (See numericalmacros.pl for one example.) - -=cut - -=head2 Other constructs +=head2 SEE ALSO See F for definitions of C and C @@ -85,6 +81,10 @@ sub push_stat_data_set { push(@accumulatedDataSets, $data); } +=head2 init_statistics_graph + +=cut + sub init_statistics_graph { my (%options) = @_; my $numberDataSets = 1 + $#accumulatedDataSets; @@ -118,6 +118,10 @@ sub init_statistics_graph { $graphRef; } +=head2 getMinMax + +=cut + sub getMinMax { # Routine to return the smallest and largest value in the list of # numbers given for the arguments to the function. @@ -131,6 +135,10 @@ sub getMinMax { ($xmin, $xmax); } +=head2 add_boxplot + +=cut + sub add_boxplot { # add_boxplot($graphRef,{"outliers"=>1}); # @@ -232,6 +240,10 @@ sub add_boxplot { $bounds; } +=head2 add_histogram + +=cut + sub add_histogram { my $graphRef = shift; my $numberBins = shift; @@ -338,6 +350,4 @@ sub add_histogram { $bounds; } -######################################################### - 1; diff --git a/macros/graph/PGtikz.pl b/macros/graph/PGtikz.pl index 51f9383df6..05add89631 100644 --- a/macros/graph/PGtikz.pl +++ b/macros/graph/PGtikz.pl @@ -26,8 +26,6 @@ =head1 DESCRIPTION image(insertGraph($image)); -=head1 DETAILED USAGE - There are several LaTeXImage parameters that may need to be set for the LaTeXImage object return by createTikZImage to generate the desired image. diff --git a/macros/graph/imageChoice.pl b/macros/graph/imageChoice.pl index 5792bb192b..0ba4c2a6fb 100644 --- a/macros/graph/imageChoice.pl +++ b/macros/graph/imageChoice.pl @@ -1,35 +1,33 @@ -loadMacros('PGchoicemacros.pl', 'unionUtils.pl', 'choiceUtils.pl',); +# Note: this depends on deprecated macros, so should be deprecated. However, there are OPL problems with this + +loadMacros('PGchoicemacros.pl', 'unionUtils.pl', 'choiceUtils.pl'); sub _imageChoice_init { }; # don't reload this file -###################################################################### -# # Create a match list where the answers are images -# + # Usage: $ml = new_image_match_list(options); -# + # where options are those that can be supplied to image_print_a below. # The answers should be an image name or reference to a plot object # (or a reference to a pair of either of these), and they are passed # to the Image function for processing. See unionUtils.pl for more # information on how these are handled. -# + sub new_image_match_list { my $ml = new Match(random(1, 2000, 1), \&alt_print_q, \&img_print_a); $ml->{ImageOptions} = [@_]; $ml; } -###################################################################### -# # A print routine for image matching. This is designed to display # four graphs per row. More can be included by setting the ImageOptions # variable in the match list. For example: -# + # $ml->{ImageOptions} = [size => [100,100]] -# + # You can include the following options: -# + # size => [w,h] the width and height of the images # width => n the width of the images (obsolete) # height => n the height of the images (obsolete) @@ -39,7 +37,6 @@ sub new_image_match_list { # link => 0 or 1 1 to make a link to the original image # columns => n the number of images in each row (defaults to 4) # border => n the width of the image border -# sub img_print_a { my $self = shift; diff --git a/macros/graph/plotly3D.pl b/macros/graph/plotly3D.pl index f731733b99..fc726af505 100644 --- a/macros/graph/plotly3D.pl +++ b/macros/graph/plotly3D.pl @@ -3,7 +3,6 @@ =head1 NAME plotly3D.pl - Adds Graph3D, an object for creating 3D parametric curves and 3D parametric surface plots using the plotly JavaScript library. -L =head1 DESCRIPTION @@ -315,6 +314,10 @@ =head1 Graph3D OPTIONS =back +=head1 SEE ALSO + +L + =cut sub _plotly3D_init { diff --git a/macros/graph/unionImage.pl b/macros/graph/unionImage.pl index ba389a266e..3e508b5693 100644 --- a/macros/graph/unionImage.pl +++ b/macros/graph/unionImage.pl @@ -1,3 +1,5 @@ +# Note: this should be deprecated, but many OPL problems depend on it. + loadMacros("unionMacros.pl"); sub _unionImage_init { }; # don't reload this file diff --git a/macros/math/MatrixCheckers.pl b/macros/math/MatrixCheckers.pl index 82c76181c4..55fd356f0a 100644 --- a/macros/math/MatrixCheckers.pl +++ b/macros/math/MatrixCheckers.pl @@ -1,10 +1,8 @@ -sub _MatrixCheckers_init { }; # don't reload this file - -=pod =head1 NAME -MatrixCheckers.pl +MatrixCheckers.pl - Provides subroutines for answer checking using MathObjects +matrices with real entries. =head1 SYNOPSIS @@ -122,17 +120,11 @@ =head1 DESCRIPTION particular solution), while the remaining vectors are a basis for the hyperplane (i.e., they span the homogeneous solution set). -=head1 AUTHORS - -Paul Pearson, Hope College, Department of Mathematics - =cut -################################################ - -loadMacros("MathObjects.pl",); # , will "parserMultiAnswer.pl" create an infinite loop? +sub _MatrixCheckers_init { }; # don't reload this file -################################################ +loadMacros("MathObjects.pl",); # , will "parserMultiAnswer.pl" create an infinite loop? sub concatenate_columns_into_matrix { @@ -145,8 +137,6 @@ sub concatenate_columns_into_matrix { } -########################################## - sub basis_checker_one_column { my ($correct, $student, $answerHash) = @_; @@ -168,8 +158,6 @@ sub basis_checker_one_column { } -########################################## - sub basis_checker_columns { my ($correct, $student, $answerHash) = @_; @@ -215,8 +203,6 @@ sub basis_checker_columns { } -############################################# - sub unit_basis_checker_one_column { my ($correct, $student, $answerHash) = @_; @@ -236,8 +222,6 @@ sub unit_basis_checker_one_column { } -############################################### - sub orthonormal_basis_checker_columns { my ($correct, $student, $answerHash) = @_; @@ -290,8 +274,6 @@ sub orthonormal_basis_checker_columns { } -############################################## - sub basis_checker_rows { my ($correct, $student, $answerHash) = @_; @@ -338,8 +320,6 @@ sub basis_checker_rows { } -############################################# - sub orthonormal_basis_checker_rows { my ($correct, $student, $answerHash) = @_; @@ -393,8 +373,6 @@ sub orthonormal_basis_checker_rows { } -############################################## - sub parametric_plane_checker_columns { my ($correct, $student, $answerHash) = @_; @@ -457,6 +435,4 @@ sub parametric_plane_checker_columns { } -######################################################## - 1; diff --git a/macros/math/MatrixReduce.pl b/macros/math/MatrixReduce.pl index c6c82c5f5c..43c847bba2 100644 --- a/macros/math/MatrixReduce.pl +++ b/macros/math/MatrixReduce.pl @@ -1,16 +1,11 @@ -sub _MatrixReduce_init { }; # don't reload this file - -=pod =head1 NAME -MatrixReduce.pl - reduced row echelon form, row -operations, and elementary matrices. +MatrixReduce.pl - reduced row echelon form, row operations, and elementary matrices. -=head1 SYNOPSIS +=head1 DESCRIPTION -Provides subroutines for elementary matrix -computations using MathObjects matrices. +Provides subroutines for elementary matrix computations using MathObjects matrices. =over 12 @@ -68,7 +63,7 @@ =head1 SYNOPSIS =back -=head1 DESCRIPTION +=head1 SYNOPSIS Usage: @@ -147,9 +142,10 @@ =head1 AUTHORS # a consistent system. Also, with randomly chosen matrices, it is # possible to get rows or columns of zeros, so watch out! +sub _MatrixReduce_init { }; # don't reload this file + loadMacros("MathObjects.pl", "contextFraction.pl",); -################################################ # rref: input and output are MathObject matrices. # Should be run in Fraction context for best results. @@ -201,7 +197,6 @@ sub rref_perl_array { return @A; } -################################################ # This was written by Davide Cervone. # http://webwork.maa.org/moodle/mod/forum/discuss.php?d=2970 @@ -216,15 +211,11 @@ sub change_matrix_entry { } } -################################################ - sub identity_matrix { my $n = shift; return Value::Matrix->I($n); } -################################################ - sub elem_matrix_row_switch { # $n = number of rows (and columns) in matrix @@ -241,8 +232,6 @@ sub elem_matrix_row_switch { } -######################################### - sub elem_matrix_row_mult { # $n = number of rows (and columns) in matrix @@ -263,8 +252,6 @@ sub elem_matrix_row_mult { } -###################################### - sub elem_matrix_row_add { # $n = number of rows (and columns) in matrix @@ -285,16 +272,14 @@ sub elem_matrix_row_add { } -############################################## - sub row_add { # put (row i) + s * (row j) into (row i) - my $M = shift; # MathObject matrix - my $i = shift; # row index - my $j = shift; # row index - my $s = shift; # scaling factor + my $M = shift; # MathObject matrix + my $i = shift; # row index + my $j = shift; # row index + my $s = shift; # scaling factor my ($r, $c) = $M->dimensions; if (($i < 1) or ($j < 1) or ($i > $r) or ($j > $r)) { @@ -318,8 +303,6 @@ sub row_add { } -#################################### - sub row_switch { my $M = shift; # MathObject matrix @@ -336,8 +319,6 @@ sub row_switch { } -######################################### - sub row_mult { my $M = shift; # MathObject matrix @@ -357,8 +338,6 @@ sub row_mult { } -#################################### - sub apply_fraction_to_matrix_entries { my $M = shift; diff --git a/macros/math/MatrixUnimodular.pl b/macros/math/MatrixUnimodular.pl index a7d9795cbd..08d3aa8c2d 100644 --- a/macros/math/MatrixUnimodular.pl +++ b/macros/math/MatrixUnimodular.pl @@ -1,11 +1,26 @@ + +=head1 NAME + +MatrixUnimodular.pl - functions and checkers for Unimodular matrices. + +=cut + sub _MatrixUnimodular_init { }; # don't reload this file -sub xgcd ($$) { +=head1 FUNCTIONS + +=head2 xgcd + +Extended greatest common divisor + +C - # Extended greatest common divisor - # xgcd( a , b ) = ( d , x , y , s , t ) - # where - # gcd(a,b) = d = a (x + s k) + b (y + t k) for any integer k +where gcd(a,b) = d = a (x + s k) + b (y + t k) for any integer k + +=cut + +# Note: this is in algebraMacros.pl. Maybe put in a common place? +sub xgcd ($$) { my ($a, $x, $y) = (int(shift), 1, 0); my ($b, $s, $t) = (int(shift), 0, 1); @@ -24,46 +39,53 @@ ($$) } } -sub unimodular_SL2Z_specific { +=head2 unimodular_SL2Z_specific + +Unimodular 2x2 matrix in SL_2(Z) +unimodular( a11, a21 ) +returns a determinant 1 matrix object + + [ a11 a12 ] + [ a21 a22 ] + +The inputs a11 and a12 must be relatively prime +integers, and could be thought of as an eigenvector. +If they are not relatively prime, then the identity +matrix will be returned. - # Unimodular 2x2 matrix in SL_2(Z) - # unimodular( a11, a21 ) - # returns a determinant 1 matrix object - # [ a11 a12 ] - # [ a21 a22 ] - # The inputs a11 and a12 must be relatively prime - # integers, and could be thought of as an eigenvector. - # If they are not relatively prime, then the identity - # matrix will be returned. +=cut - my $a11 = shift; - my $a21 = shift; +sub unimodular_SL2Z_specific { + my ($a11, $a21) = @_; my @w = xgcd($a11, $a21); # "weights" if ($w[0] != 1) { return (1, 0, 0, 1); } - # my $a12 = -($w[2]); - # my $a22 = $w[1]; - @A = ($a11, $a21, -($w[2]), $w[1]); + return ($a11, $a21, -($w[2]), $w[1]); +} + +=head2 unimodular_SL2Z - return @A; +Unimodular 2x2 matrix in SL_2(Z) -} +unimodular ( A, B ) = ( a11, a21, a12, a22 ) -sub unimodular_SL2Z { + where + + [ a11 a12 ] + [ a21 a22 ] - # Unimodular 2x2 matrix in SL_2(Z) - # unimodular ( A, B ) = ( a11, a21, a12, a22 ) - # where - # [ a11 a12 ] - # [ a21 a22 ] - # is a determinant one matrix with integer entries - # and the inputs A < B are the limits of the size of the entries - # If they are not relatively prime, then the identity - # matrix will be returned. - # Note: it returns a matrix listed by columns (not rows) - # so that you can easily use the columns as eigenvectors +is a determinant one matrix with integer entries +and the inputs A < B are the limits of the size of the entries +If they are not relatively prime, then the identity +matrix will be returned. +Note: it returns a matrix listed by columns (not rows) +so that you can easily use the columns as eigenvectors + +=cut + +sub unimodular_SL2Z { my $a11 = list_random(-7, -5, -3, -2, 2, 3, 5, 7); my $a21 = list_random(-7, -5, -3, -2, 2, 3, 5, 7); @@ -72,29 +94,28 @@ sub unimodular_SL2Z { } my @w = xgcd($a11, $a21); + return ($a11, $a21, -($w[2]), $w[1]); +} - # my $a12 = -($w[2]); - # my $a22 = $w[1]; +=head1 unimodular_GL2Z - my @A = ($a11, $a21, -($w[2]), $w[1]); +Unimodular 2x2 matrix in GL_2(Z) - return @A; +unimodular ( A, B ) = ( a11, a21, a12, a22, det ) where -} + [ a11 a12 ] + [ a21 a22 ] -sub unimodular_GL2Z { +is a determinant 1 or -1 matrix with integer entries +and det is the determinant. +If they are not relatively prime, then the identity +matrix will be returned. +Note: it returns a matrix listed by columns (not rows) +so that you can easily use the columns as eigenvectors. + +=cut - # Unimodular 2x2 matrix in GL_2(Z) - # unimodular ( A, B ) = ( a11, a21, a12, a22, det ) - # where - # [ a11 a12 ] - # [ a21 a22 ] - # is a determinant 1 or -1 matrix with integer entries - # and det is the determinant. - # If they are not relatively prime, then the identity - # matrix will be returned. - # Note: it returns a matrix listed by columns (not rows) - # so that you can easily use the columns as eigenvectors. +sub unimodular_GL2Z { my $a11 = list_random(-7, -5, -3, -2, 2, 3, 5, 7); my $a21 = list_random(-7, -5, -3, -2, 2, 3, 5, 7); @@ -109,23 +130,24 @@ sub unimodular_GL2Z { my $s = random(-1, 1, 2); # randomize the sign for the first column - my @A = ($s * $a11, $s * $a21, -($w[2]), $w[1]); + return ($s * $a11, $s * $a21, -($w[2]), $w[1]); +} + +=head2 unimodular_diagonalization_SL2Z - return @A; +input: two distinct integer eigenvalues (lambda1, lambda2) -} +output: a single array with the following entries in order: -sub unimodular_diagonalization_SL2Z { +2x2 matrix listed by columns (A11,A21,A12,A22), +first eigenvalue lambda1, first eigenvector (P11,P21), +second eigenvalue lambda2, second eigenvector (P12,P22) - # input: two distinct integer eigenvalues (lambda1, lambda2) - # - # output: a single array with the following entries in order: - # 2x2 matrix listed by columns (A11,A21,A12,A22), - # first eigenvalue lambda1, first eigenvector (P11,P21), - # second eigenvalue lambda2, second eigenvector (P12,P22) +=cut - my $lambda1 = shift; - my $lambda2 = shift; +sub unimodular_diagonalization_SL2Z { + + my ($lambda1, $lambda2) = @_; my @P = unimodular_SL2Z(); @@ -142,17 +164,20 @@ sub unimodular_diagonalization_SL2Z { } -sub unimodular_diagonalization_GL2Z { +=head2 unimodular_diagonalization_GL2Z + +input: two distinct integer eigenvalues (lambda1, lambda2) + +output: a single array with the following entries in order: - # input: two distinct integer eigenvalues (lambda1, lambda2) - # - # output: a single array with the following entries in order: - # 2x2 matrix listed by columns (M11,M21,M12,M22), - # first eigenvalue lambda1, first eigenvector (P11,P21), - # second eigenvalue lambda2, second eigenvector (P12,P22) +2x2 matrix listed by columns (M11,M21,M12,M22), +first eigenvalue lambda1, first eigenvector (P11,P21), +second eigenvalue lambda2, second eigenvector (P12,P22) - my $lambda1 = shift; - my $lambda2 = shift; +=cut + +sub unimodular_diagonalization_GL2Z { + my ($lambda1, $lambda2) = @_; my @P = unimodular_GL2Z(); my $detP = $P[0] * $P[3] - $P[1] * $P[2]; @@ -166,25 +191,29 @@ sub unimodular_diagonalization_GL2Z { ); return (@A, @P, $lambda1, $lambda2); - } -############################################################### -# Versions with small integer entries +=head2 small_unimodular_GL2Z -sub small_unimodular_GL2Z { +Unimodular 2x2 matrix in GL_2(Z) + +unimodular ( A, B ) = ( a11, a21, a12, a22, det ) + +where + + [ a11 a12 ] + [ a21 a22 ] - # Unimodular 2x2 matrix in GL_2(Z) - # unimodular ( A, B ) = ( a11, a21, a12, a22, det ) - # where - # [ a11 a12 ] - # [ a21 a22 ] - # is a determinant 1 or -1 matrix with integer entries - # and det is the determinant. - # If they are not relatively prime, then the identity - # matrix will be returned. - # Note: it returns a matrix listed by columns (not rows) - # so that you can easily use the columns as eigenvectors. +is a determinant 1 or -1 matrix with integer entries +and det is the determinant. +If they are not relatively prime, then the identity +matrix will be returned. +Note: it returns a matrix listed by columns (not rows) +so that you can easily use the columns as eigenvectors. + +=cut + +sub small_unimodular_GL2Z { my $a11 = list_random(-4, -3, -2, 2, 3, 4); my $a21 = list_random(-4, -3, -2, 2, 3, 4); @@ -194,28 +223,25 @@ sub small_unimodular_GL2Z { my @w = xgcd($a11, $a21); - # my $a12 = -($w[2]); - # my $a22 = $w[1]; - my $s = random(-1, 1, 2); # randomize the sign for the first column - my @A = ($s * $a11, $s * $a21, -($w[2]), $w[1]); + return ($s * $a11, $s * $a21, -($w[2]), $w[1]); +} - return @A; +=head2 small_unimodular_diagonalization_GL2Z -} +input: two distinct integer eigenvalues (lambda1, lambda2) -sub small_unimodular_diagonalization_GL2Z { +output: a single array with the following entries in order: + +2x2 matrix listed by columns (M11,M21,M12,M22), +first eigenvalue lambda1, first eigenvector (P11,P21), +second eigenvalue lambda2, second eigenvector (P12,P22) - # input: two distinct integer eigenvalues (lambda1, lambda2) - # - # output: a single array with the following entries in order: - # 2x2 matrix listed by columns (M11,M21,M12,M22), - # first eigenvalue lambda1, first eigenvector (P11,P21), - # second eigenvalue lambda2, second eigenvector (P12,P22) +=cut - my $lambda1 = shift; - my $lambda2 = shift; +sub small_unimodular_diagonalization_GL2Z { + my ($lambda1, $lambda2) = @_; my @P = small_unimodular_GL2Z(); my $detP = $P[0] * $P[3] - $P[1] * $P[2]; diff --git a/macros/math/MatrixUnits.pl b/macros/math/MatrixUnits.pl index 1b32f3c025..0ea8402460 100644 --- a/macros/math/MatrixUnits.pl +++ b/macros/math/MatrixUnits.pl @@ -1,25 +1,19 @@ -=pod - =head1 NAME -MatrixUnits.pl - -=head1 SYNOPSIS - -Generates unimodular n x n (n=2,3,4) MathObject matrices with real entries. +MatrixUnits.pl - Generates unimodular n x n (n=2,3,4) MathObject matrices with real entries. =head1 DESCRIPTION -This macro provides some routines for generating n x n (n=2,3,4) -MathObject matrices with real entries that have determinant in the -group of units of the integers Z (i.e., are Z-invertible). A matrix -C<$M = GLnZ();> (for det = +1 or -1) or <$M = SLnZ();> (for det = -1) +This macro provides some routines for generating n x n (n=2,3,4) +MathObject matrices with real entries that have determinant in the +group of units of the integers Z (i.e., are Z-invertible). A matrix +C<$M = GLnZ();> (for det = +1 or -1) or <$M = SLnZ();> (for det = -1) has all integer entries, is invertible, and its inverse has all integer entries. The matrix entries are intentionally chosen to be integers close to zero (so, if you want unimodular matrices with larger integer entries, you may want to copy the source code and modify it to suit your needs). -The basic idea is to multiply several elementary matrices of +The basic idea is to multiply several elementary matrices of determinant +1 or -1 together to get a unimodular matrix (although the code below accomplishes this by elementary row operations rather than by multiplication of elementary matrices). @@ -36,34 +30,27 @@ =head1 DESCRIPTION =back -Note that the indexing on MathObject matrices starts at 1, while the indexing +Note that the indexing on MathObject matrices starts at 1, while the indexing on perl arrays starts at 0, so that C<$A-element(1,1);> corresponds to C<$a[0][0];>. The perl arrays can be made into MathObject matrices by C<$A = Matrix(\@a);>, and this is, in fact, what the C and C -subroutines do for you. The perl versions C<@a = GLnZ_perl()> and -C<@a = SLnZ_perl()> are useful if you want to have quick access to the matrix -values (as perl reals stored in C<@a>) without having to pull them out of a +subroutines do for you. The perl versions C<@a = GLnZ_perl()> and +C<@a = SLnZ_perl()> are useful if you want to have quick access to the matrix +values (as perl reals stored in C<@a>) without having to pull them out of a MathObject matrix via C<@b = $A-value;> (in which case C<@b> is an array of MathObject reals). -Note: There is overlap between MatrixUnits.pl (written after MathObject +Note: There is overlap between MatrixUnits.pl (written after MathObject matrices were created) and MatrixUnimodular.pl (written before MathObject matrices were created). MatrixUnimodular.pl was left unchanged to provide legacy support for existing PG files. -=head1 AUTHORS - -Paul Pearson, Hope College, Department of Mathematics - =cut sub _MatrixUnits_init { }; # don't reload this file loadMacros("MathObjects.pl",); -################################################ -# - sub GL2Z { my @a = GL2Z_perl(); return Matrix(\@a); @@ -302,6 +289,4 @@ sub SL4Z_perl { } -################################################## - 1; diff --git a/macros/math/PCCfactor.pl b/macros/math/PCCfactor.pl index d9c517548e..b318336461 100644 --- a/macros/math/PCCfactor.pl +++ b/macros/math/PCCfactor.pl @@ -1,28 +1,37 @@ -# The subroutine factoringMethodsis takes arguments -# ($a[0], $a[1], $b[0], $b[1], $var[0], $var[1]) -# corresponding to a factored polynomial -# (a[0] $var[0]+b[0] $var[1])(a[1] $var[0]+b[1] $var[1]) -# @a and @b should be integers, and doctored in the problem code so -# that gcd(@a) and gcd(@b) equal 1. -# @var should be variables that have been added to the context. -# $var[1] is optional. - -# The output includes various methods to factor the polynomial, -# including: -# * number sense method -# * formula method (perfect squares and difference of squares) -# * ac method -# * guess-and-check with generic rectangles method - -# If $var[1] is omitted and $var[0] is something like 'xy', then both -# letters should be variables added to the context, and the expanded -# (unfactored) versions of polynomials will be shown like -# Ax^2y^2 + Bxy + C -# instead of -# A(xy)^2 + Bxy + C -# and the factorization is -# (a[0] $var[2] $var[3] + b[0])(a[1] $var[2] $var[3] + b[1]) -# where $var[2] and $var[3] are the individual letters form the given $var[0] + +=head1 NAME + +PCCfactor.pl - provide some convience routines for factoring qudartics. + +=head1 DESCRIPTION + +The subroutine factoringMethodsis takes arguments +($a[0], $a[1], $b[0], $b[1], $var[0], $var[1]) +corresponding to a factored polynomial +(a[0] $var[0]+b[0] $var[1])(a[1] $var[0]+b[1] $var[1]) +@a and @b should be integers, and doctored in the problem code so +that gcd(@a) and gcd(@b) equal 1. +@var should be variables that have been added to the context. +$var[1] is optional. + + The output includes various methods to factor the polynomial, + including: + * number sense method + * formula method (perfect squares and difference of squares) + * ac method + * guess-and-check with generic rectangles method + +If $var[1] is omitted and $var[0] is something like 'xy', then both +letters should be variables added to the context, and the expanded +(unfactored) versions of polynomials will be shown like +Ax^2y^2 + Bxy + C +instead of +A(xy)^2 + Bxy + C +and the factorization is +(a[0] $var[2] $var[3] + b[0])(a[1] $var[2] $var[3] + b[1]) +where $var[2] and $var[3] are the individual letters form the given $var[0] + +=cut loadMacros("MathObjects.pl", "PGgraphmacros.pl"); @@ -90,7 +99,8 @@ sub factoringMethods { $BBOLD . 'Perfect Square Formula: ' . $EBOLD - . 'The formula for perfect square trinomials is \[(a \pm b)^2=a^2 \pm 2ab + b^2\] Note that the polynomial \(' + . 'The formula for perfect square trinomials is \[(a \pm b)^2=a^2 \pm 2ab + b^2\]. ' + . 'Note that the polynomial \(' . $expanded->TeX . '\) matches the formula' . "'" . 's right side, and we have: \[\begin{aligned}[t]' @@ -147,7 +157,9 @@ sub factoringMethods { $BBOLD . 'Mental Method: ' . $EBOLD - . 'When we factor a polynomial in the form of \(x^2+bx+c\), \(x^2+bxy+cy^2\), or \(x^2y^2+bxy+c\) we can use mental math to factor. We need to find two numbers whose product is \(c\), and whose sum is \(b\).' + . 'When we factor a polynomial in the form of \(x^2+bx+c\), \(x^2+bxy+cy^2\), or \(x^2y^2+bxy+c\) ' + . 'we can use mental math to factor. We need to find two numbers whose product is \(c\), ' + . 'and whose sum is \(b\).' . $PAR . 'For \(' . $expanded->TeX @@ -201,7 +213,8 @@ sub factoringMethods { $BBOLD . 'AC Method: ' . $EBOLD - . 'In this method, we first calculate the product of \(a\) and \(c\) in \(ax^2+bx+c\). For this problem, we have \((' + . 'In this method, we first calculate the product of \(a\) and \(c\) in \(ax^2+bx+c\). ' + . 'For this problem, we have \((' . $co[0] . ') \cdot (' . $co[2] . ') = ' @@ -366,11 +379,15 @@ sub factoringMethods { } $picture[1]->lb(new Label($x[0] - $gap, $y[1] - $squareLength / 4, "$box1Left", 'black', 'right', 'middle')); - $alt1 = - "The graph has four generic rectangles. The top left rectangle has $box1 in it, and the bottom right rectangle has $box4 in it."; + $alt1 = "The graph has four generic rectangles. The top left rectangle has $box1 in it, and " + . "the bottom right rectangle has $box4 in it."; $alt2 = - "The graph has four generic rectangles. The top left rectangle has $box1 in it; the top right rectangle has $box2 in it; the bottom left rectangle has $box3 in it; and the bottom right rectangle has $box4 in it. $box1Up is marked above the top left rectangle; $box1Left is marked to the left of the top left rectangle; $box2Up is marked above the top right rectangle; $box3Left is marked to the left of the bottom left rectangle."; + "The graph has four generic rectangles. The top left rectangle has $box1 in it; " + . "the top right rectangle has $box2 in it; the bottom left rectangle has $box3 in it; " + . "and the bottom right rectangle has $box4 in it. $box1Up is marked above the top left " + . "rectangle; $box1Left is marked to the left of the top left rectangle; $box2Up is marked " + . "above the top right rectangle; $box3Left is marked to the left of the bottom left rectangle."; #### End two pictures ### @@ -415,7 +432,8 @@ sub factoringMethods { . $PAR . "The first term\'s coefficient, \\(" . $co[0] - . '\), can be factored into the product of two numbers (where the first factor is positive) in the following ways: \[\begin{array}{llll}' + . '\), can be factored into the product of two numbers (where the first factor is positive) ' + . 'in the following ways: \[\begin{array}{llll}' . $factorPairsAOutput . '\end{array}\]' . $PAR @@ -425,7 +443,8 @@ sub factoringMethods { . $factorPairsCOutput . '\end{array}\]' . $PAR - . 'We put each pair into the corresponding places next to those generic rectangles, and try to match the area of those rectangles with \(' + . 'We put each pair into the corresponding places next to those generic rectangles, and try to ' + . 'match the area of those rectangles with \(' . $expanded->TeX . '\) by guess-and-check. The following generic rectangles show the solution:' . $PAR diff --git a/macros/math/PGdiffeqmacros.pl b/macros/math/PGdiffeqmacros.pl index 483fcbb661..3d79f708a2 100644 --- a/macros/math/PGdiffeqmacros.pl +++ b/macros/math/PGdiffeqmacros.pl @@ -1,7 +1,9 @@ -=head1 PGdiffeqmacros.pl DESCRIPTION +# Note: this needs to be deprecated. But in a lot problems. -# Macros for Prills 163 problems +=head1 NAME + +PGdiffeqmacros.pl - Macros for Prills 163 problems =cut diff --git a/macros/math/PGmatrixmacros.pl b/macros/math/PGmatrixmacros.pl index a7a926ab0a..4108be28a8 100644 --- a/macros/math/PGmatrixmacros.pl +++ b/macros/math/PGmatrixmacros.pl @@ -1,7 +1,8 @@ +# Note: should be deprecated. Built-in to Matrix MathObjects. =head1 NAME -Matrix macros for the PG language +PGmatrixmacros.pl - Matrix macros for the PG language =head1 DESCRIPTION diff --git a/macros/math/PGmorematrixmacros.pl b/macros/math/PGmorematrixmacros.pl index 43ddbf161f..8a9c82c6fc 100644 --- a/macros/math/PGmorematrixmacros.pl +++ b/macros/math/PGmorematrixmacros.pl @@ -1,7 +1,8 @@ +# Note: move this functionality into the Matrix MathObject. =head1 NAME -More matrix macros for the PG language +PGmorematrixmacros.pl - More matrix macros for the PG language =head1 DESCRIPTION @@ -14,12 +15,6 @@ =head1 DESCRIPTION # set the prefix used for arrays. our $ArRaY = $main::PG->{ARRAY_PREFIX}; -=head2 NAME - - macros/PGmorematrixmacros.pl - -=cut - sub _PGmorematrixmacros_init { } =head2 random_inv_matrix diff --git a/macros/math/PGnauBinpacking.pl b/macros/math/PGnauBinpacking.pl index a9103ba2b4..5a6e00f092 100644 --- a/macros/math/PGnauBinpacking.pl +++ b/macros/math/PGnauBinpacking.pl @@ -1,3 +1,12 @@ + +# Note: deprecate or update POD. + +=head1 NAME + +PGnauBinpacking.pl - + +=cut + sub PGnextfit { my ($binsize, @input) = @_; my (@list, $val); diff --git a/macros/math/PGnauGraphCatalog.pl b/macros/math/PGnauGraphCatalog.pl index c8f705fd11..b955d4836d 100644 --- a/macros/math/PGnauGraphCatalog.pl +++ b/macros/math/PGnauGraphCatalog.pl @@ -1,3 +1,11 @@ +# Note: deprecate or update POD. + +=head1 NAME + +PGnauGraphCatalog.pl - + +=cut + # All simple graphs with fewer than 8 vertices push @graph1, "0;"; diff --git a/macros/math/PGnauGraphtheory.pl b/macros/math/PGnauGraphtheory.pl index 14f827fd62..2e3c698140 100644 --- a/macros/math/PGnauGraphtheory.pl +++ b/macros/math/PGnauGraphtheory.pl @@ -1,4 +1,11 @@ -# PGgraphtheory.pl + +# Note: deprecate or update POD. + +=head1 NAME + +PGnauGraphics.pl - + +=cut loadMacros("PGnauGraphics.pl",); diff --git a/macros/math/PGnauScheduling.pl b/macros/math/PGnauScheduling.pl index 2a5ba74237..756d8914d0 100644 --- a/macros/math/PGnauScheduling.pl +++ b/macros/math/PGnauScheduling.pl @@ -1,4 +1,12 @@ +# Note: deprecate or update POD. + +=head1 NAME + +PGnauScheduling.pl - + +=cut + ##################################################################### # # Name : ListProcEval (answer evaluator for the scheduling .pg files) diff --git a/macros/math/PGnauSet.pl b/macros/math/PGnauSet.pl index 1a4d453014..ce77fd59df 100644 --- a/macros/math/PGnauSet.pl +++ b/macros/math/PGnauSet.pl @@ -1,3 +1,12 @@ + +# Note: deprecate or update POD. + +=head1 NAME + +PGnauSet.pl - + +=cut + loadMacros("PGnauGraphics.pl",); ####################################################################################################### diff --git a/macros/math/PGnauStats.pl b/macros/math/PGnauStats.pl index 6762dd59c2..61e8f2b26c 100644 --- a/macros/math/PGnauStats.pl +++ b/macros/math/PGnauStats.pl @@ -1,3 +1,12 @@ + +# Note: deprecate or update POD. + +=head1 NAME + +PGnauStats.pl - + +=cut + loadMacros("PGnauGraphics.pl",); ################################ diff --git a/macros/math/PGnumericalmacros.pl b/macros/math/PGnumericalmacros.pl index 87e6791fd5..e949dcc98b 100644 --- a/macros/math/PGnumericalmacros.pl +++ b/macros/math/PGnumericalmacros.pl @@ -1,7 +1,7 @@ =head1 NAME -Numerical methods for the PG language +PGnumericalmacros.pl - Numerical methods for the PG language =cut @@ -9,9 +9,9 @@ =head1 NAME sub _PGnumericalmacros_init { } -=head2 Interpolation methods +=head1 Interpolation methods -=head3 plot_list +=head2 plot_list Usage: @@ -68,7 +68,7 @@ sub plot_list { }; } -=head3 horner +=head2 horner Usage: @@ -108,7 +108,7 @@ sub horner { }; } -=head3 hermite +=head2 hermite Usage: @@ -162,7 +162,7 @@ sub hermite { return horner(\@zvals, \@output); } -=head3 hermite_spline +=head2 hermite_spline Usage @@ -225,7 +225,7 @@ sub hermite_spline { }; } -=head3 cubic_spline +=head2 cubic_spline Usage: @@ -379,9 +379,9 @@ sub javaScript_cubic_spline { return $output_str; } -=head2 Numerical Integration methods +=head1 Numerical Integration methods -=head3 lefthandsum +=head2 lefthandsum Left Hand Riemann Sum @@ -409,7 +409,7 @@ sub lefthandsum { return $sum * $delta; } -=head3 righthandsum +=head2 righthandsum Right Hand Riemann Sum @@ -437,7 +437,7 @@ sub righthandsum { return $sum * $delta; } -=head3 midpoint +=head2 midpoint Usage: @@ -463,7 +463,7 @@ sub midpoint { return $sum * $delta; } -=head3 simpson +=head2 simpson Usage: @@ -494,7 +494,7 @@ sub simpson { return $sum * $delta / 3; } -=head3 trapezoid +=head2 trapezoid Usage: @@ -521,7 +521,7 @@ sub trapezoid { return $sum * $delta; } -=head3 romberg +=head2 romberg Usage: @@ -545,7 +545,7 @@ sub romberg_iter { / (4**($k - 1) - 1); } -=head3 inv_romberg +=head2 inv_romberg Inverse Romberg @@ -590,9 +590,9 @@ sub inv_romberg { return $b; } -=head2 Differential Equation Methods +=head1 Differential Equation Methods -=head3 rungeKutta4 +=head2 rungeKutta4 Finds integral curve of a vector field using the 4th order Runge Kutta method by providing the function C diff --git a/macros/math/PGpolynomialmacros.pl b/macros/math/PGpolynomialmacros.pl index e391b69949..aa3480d81d 100644 --- a/macros/math/PGpolynomialmacros.pl +++ b/macros/math/PGpolynomialmacros.pl @@ -1,8 +1,12 @@ -=head1 PGpolynomialmacros.pl DESCRIPTION +=head1 NAME + +PGpolynomialmacros.pl - this macro contains routines use to create and manipulate polynomials. + +=head1 DESCRIPTION ########################################################## - # It contains rountines used to create and manipulate ## + # It contains routines used to create and manipulate ## # polynomials for WeBWorK ## # ## # Copyright 2002 Mark Schmitt ## diff --git a/macros/math/PGstatisticsmacros.pl b/macros/math/PGstatisticsmacros.pl index 45b8e81a99..3d44fe94cf 100644 --- a/macros/math/PGstatisticsmacros.pl +++ b/macros/math/PGstatisticsmacros.pl @@ -1,19 +1,11 @@ -sub _PGstatisticsmacros_init { - foreach my $t (@Distributions::EXPORT_OK) { - *{$t} = *{"Distributions::$t"}; - } - foreach my $t (@Regression::EXPORT_OK) { - *{$t} = *{"Regression::$t"}; - } - foreach my $t (@Statistics::EXPORT_OK) { - *{$t} = *{"Statistics::$t"}; - } -} +=head1 NAME + +PGstatisticsmacros.pl - functions for calculating statistics measures. -=head1 Statistics Macros +=head1 FUNCTIONS -=head2 Normal distribution +=head2 normal_prob =pod @@ -25,6 +17,18 @@ =head2 Normal distribution =cut +sub _PGstatisticsmacros_init { + foreach my $t (@Distributions::EXPORT_OK) { + *{$t} = *{"Distributions::$t"}; + } + foreach my $t (@Regression::EXPORT_OK) { + *{$t} = *{"Regression::$t"}; + } + foreach my $t (@Statistics::EXPORT_OK) { + *{$t} = *{"Statistics::$t"}; + } +} + sub normal_prob { my $a = shift; my $b = shift; @@ -69,9 +73,10 @@ sub normal_prob { return $prob; } -=head2 "Inverse" of normal distribution +=head2 normal_distr + +"Inverse" of normal distribution -=pod Usage: normal_distr(prob, mean=>0, deviation=>1); @@ -107,9 +112,9 @@ sub normal_distr { $b; } -=head2 Mean function +=head2 stats_mean -=pod +Mean function Usage: stats_mean(@data); @@ -131,11 +136,11 @@ sub stats_mean { } -=head2 Standard Deviation function +=head2 stats_sd -=pod +Standard Deviation function - Usage: stats_sd(@data); + Usage: stats_sd(@data); Computes the sample standard deviation of a list of numbers, data. You may also pass the numbers individually. @@ -153,11 +158,11 @@ sub stats_sd { } -=head2 Sum and Sum of Squares +=head2 stats_SX_SXX -=pod +Sum and Sum of Squares - Usage: stats_SX_SXX(@data); + Usage: stats_SX_SXX(@data); Computes the sum of the numbers and the sum of the numbers squared. @@ -177,11 +182,13 @@ sub stats_SX_SXX { ($sum_x, $sum_squares); } -=head2 Function to trim the decimal numbers in a floating point number. +=head2 significant_decimals -=pod +Function to trim the decimal numbers in a floating point number. - Usage: significant_decimals(x,n) +Usage: + + significant_decimals(x,n) Trims the number x to have n decimal digit. ex: significant_decimals(0.12345678,4) = 0.1235 @@ -204,11 +211,13 @@ sub significant_decimals { return (int($x * $power + 0.5) / $power); } -=head2 Function to generate normally distributed random numbers +=head2 urand -=pod +Function to generate normally distributed random numbers - Usage: urand(mean,sd,N,digits) +Usage + + urand(mean,sd,N,digits) Generates N normally distributed random numbers with the given mean and standard deviation. The digits is the number of decimal digits to use. @@ -251,13 +260,15 @@ sub urand { # generate normally dist. random numbers return @numbers; } -=head2 Function to generate exponentially distributed random numbers +=head2 exprand -=pod +Function to generate exponentially distributed random numbers + +Usage: - Usage: exprand(lambda,N,digits) + exprand(lambda,N,digits) -Generates N exponentially distributed random numbers with the given parameter, lambda. The digits is the number of decimal digits to use. +Generates N exponentially distributed random numbers with the given parameter, lambda. The digits is the number of decimal digits to use. =cut @@ -286,11 +297,13 @@ sub exprand { # generate exponentially dist. numbers Exp(x,lambda) } -=head2 Function to generate Poisson distributed random numbers +=head2 poissonrand -=pod +Function to generate Poisson distributed random numbers + +Usage: - Usage: poissonrand(lambda,N) + poissonrand(lambda,N) Generates N Poisson distributed random numbers with the given parameter, lambda. @@ -333,11 +346,13 @@ sub poissonrand { # generate random, Poisson dist. numbers Pois(lambda) } -=head2 Function to generate Binomial distributed random numbers +=head2 binomrand -=pod +Function to generate Binomial distributed random numbers + +Usage - Usage: binomrand(p,N,num) + binomrand(p,N,num) Generates num binomial distributed random numbers with parameters p and N. @@ -388,11 +403,13 @@ sub binomrand { # generate random, binomial dist. numbers Bin(n,p) } -=head2 Function to generate Bernoulli distributed random numbers +=head2 bernoullirand -=pod +Function to generate Bernoulli distributed random numbers + +Usage: - Usage: bernoullirand(p,num,{"success"=>"1","failure"=>"0"}) + bernoullirand(p,num,{"success"=>"1","failure"=>"0"}) Generates num Bernoulli distributed random numbers with parameter p. The value for a success is given by the optional "success" parameter. The @@ -447,28 +464,29 @@ sub bernoullirand { # generate random, Bernoulli dist. numbers B(p) } -=head2 Generate random values from a discrete distribution. +=head2 discreterand -=pod +Generate random values from a discrete distribution. - Usage: discreterand($n,@tableOfProbabilities) +Usage: + + discreterand($n,@tableOfProbabilities) - Example: +Example: -my $total = 10; -my @probabilities = ( [0.1,"A"], + my $total = 10; + my @probabilities = ( [0.1,"A"], [0.4,"B"], [0.3,"C"], [0.2,"D"]); -@result = discreterand($total,@probabilities); -$data = ''; -foreach $lupe (@result) -{ - $data .= $lupe . ", "; -} -$data =~ s/,$//; + @result = discreterand($total,@probabilities); + $data = ''; + for $lupe (@result) { + $data .= $lupe . ", "; + } + $data =~ s/,$//; This routine will generate num random results. The distribution is in the given array. Each element in the array is itself an array. The @@ -521,14 +539,17 @@ sub discreterand { # generate random, values based on a given table @result; } -=head2 Chi Squared statistic for a two way table +=head2 chisqrTable -=pod +Chi Squared statistic for a two way table - Usage: chisqrTable(@frequencies) +Usage: + + chisqrTable(@frequencies) + +Example: - Example: - @row1 = (1,2,2,2); + @row1 = (1,2,2,2); @row2 = (3,1,2,4); @row3 = (1,4,2,1); @row4 = (3,1,4,3); @@ -540,7 +561,9 @@ =head2 Chi Squared statistic for a two way table push(@table,~~@row5); ($chiSquared,$df) = chisqrTable(@table); -Computes the Chi Squared test statistic for a two way frequency table. Returns the test statistic and the number of degrees of freedom. The array used in the argument is a list of references to arrays that have the frequencies for each row. If one of the rows has a different number of entries than the others the routine will throw an error. +Computes the Chi Squared test statistic for a two way frequency table. Returns the test statistic and the number +of degrees of freedom. The array used in the argument is a list of references to arrays that have the frequencies +for each row. If one of the rows has a different number of entries than the others the routine will throw an error. =cut @@ -612,14 +635,15 @@ sub chisqrTable { # Given a two-way frequency table calculates the chi-square ($chiSquared, ($rows - 1) * ($columns - 1)); } -=head2 Calc the results of a t-test. +=head2 t_test -=pod +Calc the results of a t-test. - Usage: ($t,$df,$p) = t_test(t_test(mu,@data); # Perform a two-sided t-test. - or: ($t,$df,$p) = t_test(t_test(mu,@data,{'test'=>'right'}); # Perform a right sided t-test - or: ($t,$df,$p) = t_test(t_test(mu,@data,{'test'=>'left'}); # Perform a left sided t-test - or: ($t,$df,$p) = t_test(t_test(mu,@data,{'test'=>'two-sided'}); # Perform a left sided t-test +Usage: + ($t,$df,$p) = t_test(t_test(mu,@data); # Perform a two-sided t-test. + ($t,$df,$p) = t_test(t_test(mu,@data,{'test'=>'right'}); # Perform a right sided t-test + ($t,$df,$p) = t_test(t_test(mu,@data,{'test'=>'left'}); # Perform a left sided t-test + ($t,$df,$p) = t_test(t_test(mu,@data,{'test'=>'two-sided'}); # Perform a left sided t-test Computes the t-statistic, the number of degrees of freedom, and the p-value after performing a t-test on the given data. the value of mu @@ -690,14 +714,17 @@ sub t_test { ($t, $N - 1, $p); } -=head2 Calc the results of a two sample t-test. +=head2 two_sample_t_test -=pod +Calc the results of a two sample t-test. - Usage: ($t,$df,$p) = two_sample_t_test(\@data1,\@data2); # Perform a two-sided t-test. - or: ($t,$df,$p) = two_sample_t_test(\@data1,\@data2,{'test'=>'right'}); # Perform a right sided t-test - or: ($t,$df,$p) = two_sample_t_test(\@data1,\@data2,{'test'=>'left'}); # Perform a left sided t-test - or: ($t,$df,$p) = two_sample_t_test(\@data1,\@data2,{'test'=>'two-sided'}); # Perform a left sided t-test + + +Usage: + ($t,$df,$p) = two_sample_t_test(\@data1,\@data2); # Perform a two-sided t-test. + ($t,$df,$p) = two_sample_t_test(\@data1,\@data2,{'test'=>'right'}); # Perform a right sided t-test + ($t,$df,$p) = two_sample_t_test(\@data1,\@data2,{'test'=>'left'}); # Perform a left sided t-test + ($t,$df,$p) = two_sample_t_test(\@data1,\@data2,{'test'=>'two-sided'}); # Perform a left sided t-test Computes the t-statistic, the number of degrees of freedom, and the p-value after performing a two sample t-test on the given data. The @@ -843,13 +870,14 @@ sub insertDataLink { return main::tag('a', href => main::alias($filePath), %$linkAttributes, $linkText); } -=head2 Five Point Summary function +=head2 five_point_summary -=pod +Five Point Summary function - Usage: five_point_summary(@data); - or: five_point_summary(@data,{method=>'includeMedian'}); - or: five_point_summary(@data,{method=>'proper'}); +Usage: + five_point_summary(@data); + five_point_summary(@data,{method=>'includeMedian'}); + five_point_summary(@data,{method=>'proper'}); Computes the five point summary of a list of numbers, data. You may also pass the numbers individually. The optional parameter can be @@ -994,11 +1022,13 @@ sub five_point_summary { } -=head2 Function to calculate the Pearson's sample correlation +=head2 sample_correlation -=pod +Function to calculate the Pearson's sample correlation - Usage: $cor = sample_correlation(~~@xData,~~@yData); +Usage: + + $cor = sample_correlation(~~@xData,~~@yData); Calculates the Pearson's sample correlation for the given data. The arguments are references to two arrays where each array contains the @@ -1034,11 +1064,13 @@ sub sample_correlation { (($N * $sumXY - $sumX * $sumY) / sqrt(($N * $sumX2 - $sumX * $sumX) * ($N * $sumY2 - $sumY * $sumY))); } -=head2 Function to calculate the linear least squares estimate for the linear relationship between two data sets +=head2 linear_regression -=pod +Function to calculate the linear least squares estimate for the linear relationship between two data sets + +Usage: - Usage: ($slope,$intercept,$var,$SXX) = linear_regression(~~@xdata,~~@ydata); + ($slope,$intercept,$var,$SXX) = linear_regression(~~@xdata,~~@ydata); Give the x data in @xdata and the t data in @ydata the least squares regression line is calculated. It also returns the variance in the @@ -1048,9 +1080,9 @@ =head2 Function to calculate the linear least squares estimate for the linear re inference procedures. Example: - @xdata = (-1,2,3,4,5,6,7); - @ydata = (6,5,6,7,8,9,11); - ($slope,$intercept,$var,$SXX) = linear_regression(~~@xdata,~~@ydata); + @xdata = (-1,2,3,4,5,6,7); + @ydata = (6,5,6,7,8,9,11); + ($slope,$intercept,$var,$SXX) = linear_regression(~~@xdata,~~@ydata); =cut @@ -1088,13 +1120,16 @@ sub linear_regression { ($slope, $intercept, $var, $SXX); } -=head2 Function to calculate the frequencies for the factors in a given data set. +=head2 frequencies -=pod +Function to calculate the frequencies for the factors in a given data set. + +Usage - Usage: %freq = frequencies(@theData) + %freq = frequencies(@theData) -Finds the factors in the data set and calculates the frequency of occurance for each factor. Returns a hash whose keys ar the factors and the associated values are the frequencies. +Finds the factors in the data set and calculates the frequency of occurance for each factor. +Returns a hash whose keys are the factors and the associated values are the frequencies. =cut @@ -1117,7 +1152,4 @@ sub frequencies { %frequency; } -########################################## - 1; - diff --git a/macros/math/SI_property_tables.pl b/macros/math/SI_property_tables.pl index f44824b615..e3e8944abe 100644 --- a/macros/math/SI_property_tables.pl +++ b/macros/math/SI_property_tables.pl @@ -1,3 +1,12 @@ + +# Note: deprecate or update POD. + +=head1 NAME + +SI_property_tables.pl - + +=cut + # SI_property_tables.pl # Rename this file (with .pl extension) and place it in your course macros directory, diff --git a/macros/math/SolveLinearEquationPCC.pl b/macros/math/SolveLinearEquationPCC.pl index 55ae8a2663..00c2bb5b5e 100644 --- a/macros/math/SolveLinearEquationPCC.pl +++ b/macros/math/SolveLinearEquationPCC.pl @@ -1,3 +1,12 @@ + +# Note: update POD. + +=head1 NAME + +SolveLinearEquationPCC.pl - + +=cut + #These three subroutines uniformize how all our "solve this equation" problems are handled. loadMacros('PCCmacros.pl'); diff --git a/macros/math/SystemsOfLinearEquationsProblemPCC.pl b/macros/math/SystemsOfLinearEquationsProblemPCC.pl index 2294938560..1dc3eba64a 100644 --- a/macros/math/SystemsOfLinearEquationsProblemPCC.pl +++ b/macros/math/SystemsOfLinearEquationsProblemPCC.pl @@ -1,4 +1,12 @@ +# Note: deprecate or update POD. + +=head1 NAME + +SystemOfLinearEquationsProblemPCC.pl - + +=cut + loadMacros('PCCmacros.pl', 'contextFraction.pl'); sub SystemOfLinearEquationsProblemSetup { @@ -11,8 +19,11 @@ sub SystemOfLinearEquationsProblemSetup { $zeroe = ($e == Fraction(0, 1)) ? 0 : 1; $zerof = ($f == Fraction(0, 1)) ? 0 : 1; -#How will the equations be displayed? -# This is tricky - we can't use Formula reductions or the fractions will be converted to decimals. So special treatment is given to "0x", "1x", and "-1x". Also, care is taken to prevent "--x" from becoming "+x" when it should just be "x". + #How will the equations be displayed? + # This is tricky - we can't use Formula reductions or the fractions will be converted to decimals. + # So special treatment is given to "0x", "1x", and "-1x". Also, care is taken to prevent "--x" from + # becoming "+x" when it should just be "x". + Context()->flags->set(reduceConstants => 0, showExtraParens => 0); $asided = $a * (-1)**$xside1; diff --git a/macros/math/VectorListCheckers.pl b/macros/math/VectorListCheckers.pl index bdd04a1292..4dbf6479d8 100644 --- a/macros/math/VectorListCheckers.pl +++ b/macros/math/VectorListCheckers.pl @@ -1,14 +1,7 @@ -sub _VectorListCheckers_init { }; # don't reload this file - -=pod =head1 NAME -VectorListCheckers.pl - -=head1 SYNOPSIS - -Provides subroutines for answer checking lists MathObjects +VectorListCheckers.pl - Provides subroutines for answer checking lists MathObjects vectors with real entries. =head1 DESCRIPTION @@ -101,7 +94,7 @@ =head1 AUTHORS =cut -################################################ +sub _VectorListCheckers_init { }; # don't reload this file loadMacros("MathObjects.pl",); diff --git a/macros/math/algebraMacros.pl b/macros/math/algebraMacros.pl index be19260d43..ffa1492fde 100644 --- a/macros/math/algebraMacros.pl +++ b/macros/math/algebraMacros.pl @@ -1,21 +1,22 @@ -# algebraMacros.pl -# define any custom subroutines you want and then use them in -# problems by including the file in loadMacros() calls. +=head1 NAME -sub _algebraMacros_init { +algebraMacros.pl - a set of functions that are useful in an algebra/number theory problems - #Possibly add initialization code here - #sub routine is not required, but prevents the macro from being re-loaded +=cut -} +sub _algebraMacros_init { } + +=head1 FUNCTIONS + +=head2 fyshuffle -######################## subroutines + fisher-yates shuffle + argument: reference to a list shuffles list in-place + returns: nothing + +=cut -# fisher-yates shuffle -# argument: reference to a list -# shuffles list in-place -# returns: nothing sub fyshuffle { my $array = shift; my $i = @$array; @@ -25,11 +26,18 @@ sub fyshuffle { } } -# extended euclidean algorithm -# by Dick Lane -# http://webwork.maa.org/moodle/mod/forum/discuss.php?d=2286 -# arguments: a, b -# returns: d, x, y, s, t where gcd( a, b ) = d = a( x + sk ) + b( y + tk ) for all k +=head2 xgcd + +extended euclidean algorithm + +arguments: a, b + +returns: d, x, y, s, t where gcd( a, b ) = d = a( x + sk ) + b( y + tk ) for all k + +=cut + +# by Dick Lane http://webwork.maa.org/moodle/mod/forum/discuss.php?d=2286 + sub xgcd ($$) { my ($a, $b, $x, $y, $s, $t) = (@_, 1, 0, 0, 1); @@ -41,10 +49,17 @@ ($$) return [ $a, $x, $y, $s, $t ]; } -# subroutine to decompose a permutation into a product of disjoint cycles. -# argument: reference to a list containing the permutation data -# that is, element 0 of the list is f(0), element 1 is f(1), etc -# returns: mathObject list of lists representing the cycle decomposition of the permutation +=head2 disjointCycles + +subroutine to decompose a permutation into a product of disjoint cycles. + +argument: reference to a list containing the permutation data that is, +element 0 of the list is f(0), element 1 is f(1), etc + +returns: mathObject list of lists representing the cycle decomposition of the permutation + +=cut + sub disjointCycles { $p = shift; @@ -81,9 +96,18 @@ sub disjointCycles { return $result; } -# subroutine to decompose a permutation into a product of transpositions ( 2-cycles ). -# argument: mathObject list of lists representing the cycle decomposition of the permutation (i.e., the output of disjointCycles() ) -# returns: mathObject list of lists representing the permutation as a list of transpositions +=head2 cyclesToTranspositions + + +subroutine to decompose a permutation into a product of transpositions ( 2-cycles ). + +argument: mathObject list of lists representing the cycle decomposition of the +permutation (i.e., the output of disjointCycles() ) + +returns: mathObject list of lists representing the permutation as a list of transpositions + +=cut + sub cyclesToTranspositions { my $listOfCycles = shift; @@ -97,13 +121,22 @@ sub cyclesToTranspositions { } } -# unlike disjointCycles, this subroutine is only used in a problem where the permutation has order > 4, so there will always be more than one element. Therefore we don't have to do any weird stuff to format the list (make parentheses display correctly) + # unlike disjointCycles, this subroutine is only used in a problem where the permutation has + # order > 4, so there will always be more than one element. Therefore we don't have to do + # any weird stuff to format the list (make parentheses display correctly) return List(@transpositions); } -# subroutine to determine the order of a permutation -# argument: a list of lists representing a permutation in the form of a product of disjoint cycles ( i.e., the output of disjointCycles() ) -# returns: mathObject integer representing the order of the permutation +=head2 cycleOrder + +subroutine to determine the order of a permutation + +argument: a list of lists representing a permutation in the form of a product of disjoint cycles ( i.e., the output of disjointCycles() ) + +returns: mathObject integer representing the order of the permutation + +=cut + sub cycleOrder { my $p = shift; # list of lists @@ -113,9 +146,16 @@ sub cycleOrder { return Compute($order); } -# subroutine to determine the parity of a permutation -# argument: a list of lists representing a permutation in the form of a product of disjoint cycles (i.e., the output of disjointCycles() ) -# returns: TRUE if the permutation is even, FALSE if the permutation is odd +=head2 isEven + +subroutine to determine the parity of a permutation + +argument: a list of lists representing a permutation in the form of a product of disjoint cycles (i.e., the output of disjointCycles() ) + +returns: TRUE if the permutation is even, FALSE if the permutation is odd + +=cut + sub isEven { my $p = shift; @@ -125,8 +165,6 @@ sub isEven { } -######################## frequently-used custom checkers - # you can call these when checking answers like this: # # ANS( $f->cmp( checker => ~~&modChecker ) ); @@ -153,6 +191,11 @@ sub isEven { # Comment: This checker is defined in algebraMacros.pl because it's used # in so many problems ############################################################################### + +=head2 modChecker + +=cut + sub modChecker { my ($correct, $student, $ansHash) = @_; # get correct and student MathObjects return ($student % $modulus == $correct % $modulus ? 1 : 0); @@ -173,6 +216,11 @@ sub modChecker { # Comment: This checker is defined in algebraMacros.pl because it's used # in so many problems ############################################################################### + +=head2 checkCycles + +=cut + sub checkCycles { my ($correct, $student, $ansHash) = @_; @@ -208,6 +256,11 @@ sub checkCycles { # Comment: This checker is defined in algebraMacros.pl because it's used # in so many problems ############################################################################### + +=head2 checkListOfTranspositions + +=cut + sub checkListOfTranspositions { my ($correct, $student, $ansHash, $value) = @_; @@ -243,8 +296,9 @@ sub checkListOfTranspositions { # read the two hashes to make sure they're the same. if not, the answer is wrong return scalar(grep { $studentPerm{$_} != $correctPerm{$_} } (1 .. @x)) ? (0) : (scalar(@$student)); -# an alternative way to do this would be to compute the permutation represented by the correct list of transpositions, then do the inverse of the student's list of transpositions (work left-to-right instead of right-to-left) on the same list, and see if it results in the identity. + # an alternative way to do this would be to compute the permutation represented by the correct + # list of transpositions, then do the inverse of the student's list of transpositions (work left-to-right + # instead of right-to-left) on the same list, and see if it results in the identity. } -############################################################################### -1; #required at end of file - a perl thing +1; diff --git a/macros/math/customizeLaTeX.pl b/macros/math/customizeLaTeX.pl index 93201497ea..bebbe58515 100644 --- a/macros/math/customizeLaTeX.pl +++ b/macros/math/customizeLaTeX.pl @@ -1,12 +1,11 @@ =head1 NAME -customizeLaTeX.pl - Defines default LaTeX constructs for certain mathematical - ideas. +customizeLaTeX.pl - Defines default LaTeX constructs for certain mathematical ideas. =head1 DESCRIPTION -The functions are loaded by default. Any/all can be overridden +The functions are loaded by default. Any/all can be overridden in your course's PGcourse.pl =cut diff --git a/macros/math/draggableProof.pl b/macros/math/draggableProof.pl index 9e1fb510c1..e55e5d23b2 100644 --- a/macros/math/draggableProof.pl +++ b/macros/math/draggableProof.pl @@ -1,25 +1,19 @@ -=encoding utf8 - =head1 NAME -draggableProof.pl +draggableProof.pl - Allows the contructions of problems with draggable statements for proofs. =head1 DESCRIPTION This macro helps the instructor create a drag-and-drop environment in which students are asked to arrange predefined statements into a correct sequence. -=head1 TERMINOLOGY - An HTML element into or out of which other elements may be dragged will be called a "bucket". An HTML element which houses a collection of buckets will be called a "bucket pool". -=head1 USAGE - To initialize a C bucket pool in a .pg problem, insert the line: $draggable = DraggableProof( @@ -32,17 +26,11 @@ =head1 USAGE Then insert the draggable proof bucket pool into the problem text with - BEGIN_TEXT - \{$draggable->ans_rule\} - END_TEXT - -for basic PG, or - BEGIN_PGML [_]{$draggable} END_PGML -for PGLM. Note the following also works, but is deprecated. However, if you +Note the following also works, but is deprecated. However, if you want your problem to be compatible with previous versions of PG this must be used. Call @@ -80,7 +68,7 @@ =head1 USAGE Their usage is explained in the example below. -=head1 EXAMPLE +=head1 SYNOPSIS DOCUMENT(); loadMacros( diff --git a/macros/math/draggableSubsets.pl b/macros/math/draggableSubsets.pl index 16edf48386..71c0c9e86f 100644 --- a/macros/math/draggableSubsets.pl +++ b/macros/math/draggableSubsets.pl @@ -1,9 +1,7 @@ -=encoding utf8 - =head1 NAME -draggableSubsets.pl +draggableSubsets.pl - Creates visual items that can be dragged into various buckets. =head1 DESCRIPTION @@ -11,7 +9,6 @@ =head1 DESCRIPTION pre-specified set of elements may be dragged to different "buckets", effectively partitioning the original set into subsets. -=head1 TERMINOLOGY An HTML element into or out of which other elements may be dragged will be called a "bucket". @@ -19,7 +16,6 @@ =head1 TERMINOLOGY An HTML element which houses a collection of buckets will be called a "bucket pool". -=head1 USAGE To initialize a C bucket pool in a .pg problem, insert the line @@ -76,13 +72,12 @@ =head1 USAGE Their usage is demonstrated in the example below. -=head1 EXAMPLE +=head1 SYNOPSIS DOCUMENT(); loadMacros( 'PGstandard.pl', 'PGML.pl', - 'MathObjects.pl', 'draggableSubsets.pl' ); diff --git a/macros/math/fixedPrecision.pl b/macros/math/fixedPrecision.pl index 37d5abddf3..ccb5bf324e 100644 --- a/macros/math/fixedPrecision.pl +++ b/macros/math/fixedPrecision.pl @@ -1,3 +1,12 @@ +# Note: perhaps move into the Numeric context and set a flag? + +=head1 NAME + +fixedPrecision.pl - sets up a context to check to a fixed precision (exact to some number of +decimal places). + +=cut + sub _fixedPrecision_init { } loadMacros('MathObjects.pl'); diff --git a/macros/math/interpMacros.pl b/macros/math/interpMacros.pl index 3232a6f298..64d831cdaa 100644 --- a/macros/math/interpMacros.pl +++ b/macros/math/interpMacros.pl @@ -1,5 +1,10 @@ -# interpMacros.pl -# Rename this file (with .pl extension) and place it in your course macros directory, +# Note: deprecate this? In a lot of problems, but maybe add to numericMacros.pl ? + +=head1 NAME + +interpMacros.pl - provide a interpolation for a set of data. + +=cut sub interpVals { $arrayLength = ($#_) / 2; @@ -30,4 +35,4 @@ sub interpVals { return $B_VAL; } -1; #required at end of file - a perl thing +1; diff --git a/macros/math/specialTrigValues.pl b/macros/math/specialTrigValues.pl index 79f9f19390..13508da926 100644 --- a/macros/math/specialTrigValues.pl +++ b/macros/math/specialTrigValues.pl @@ -1,10 +1,10 @@ -=head1 specialTrigValues.pl +=head1 NAME -Subroutines for converting numbers that arise in a trigonometry setting into +specialTrigValues.pl - Subroutines for converting numbers that arise in a trigonometry setting into "nice" expressions like pi/4 and sqrt(3)/2 -=head2 Description +=head1 DESCRIPTION C returns a MathObject Formula in Complex context of the form "a sqrt(b)/c" that is the closest possible to x, where a is an integer, diff --git a/macros/math/tableau_main_subroutines.pl b/macros/math/tableau_main_subroutines.pl index 67a027cba1..8afa5a9346 100644 --- a/macros/math/tableau_main_subroutines.pl +++ b/macros/math/tableau_main_subroutines.pl @@ -1,3 +1,11 @@ +# Note: Much of this is duplicated by LinearProgramming.pl. Deprecate. + +=head1 NAME + +tableau_main_subroutines.pl - + +=cut + # subroutines included into the main:: package. package main; diff --git a/macros/misc/PGunion.pl b/macros/misc/PGunion.pl index fb101a5866..249755df63 100644 --- a/macros/misc/PGunion.pl +++ b/macros/misc/PGunion.pl @@ -1,3 +1,4 @@ +# Note: this should probably be deprecated. # # Load most of the interesting code developed at Union. # diff --git a/macros/misc/unionMacros.pl b/macros/misc/unionMacros.pl index 784911774d..a37e864c17 100644 --- a/macros/misc/unionMacros.pl +++ b/macros/misc/unionMacros.pl @@ -1,3 +1,5 @@ +# Note: deprecate + ###################################################################### # # Some macros that add to the ones like $PAR, $BR, etc. diff --git a/macros/misc/unionMessages.pl b/macros/misc/unionMessages.pl index a62c6057d9..36c5ddb4ee 100644 --- a/macros/misc/unionMessages.pl +++ b/macros/misc/unionMessages.pl @@ -1,3 +1,5 @@ +# Note: deprecate + sub _unionMessages_init { } loadMacros("unionMacros.pl"); diff --git a/macros/misc/unionProblem.pl b/macros/misc/unionProblem.pl index 60701e50b6..bfbbdf20de 100644 --- a/macros/misc/unionProblem.pl +++ b/macros/misc/unionProblem.pl @@ -1,4 +1,4 @@ -#!/usr/local/bin/perl +# Note: deprecate sub _unionProblem_init { } diff --git a/macros/misc/unionUtils.pl b/macros/misc/unionUtils.pl index 30f83ddc9d..a9224698d2 100644 --- a/macros/misc/unionUtils.pl +++ b/macros/misc/unionUtils.pl @@ -1,3 +1,5 @@ +# Note: deprecate + ###################################################################### ## ## These are some miscellaneous routines that may be useful. diff --git a/macros/parsers/parserDifferenceQuotient.pl b/macros/parsers/parserDifferenceQuotient.pl index 39e528f036..5a14b37c2b 100644 --- a/macros/parsers/parserDifferenceQuotient.pl +++ b/macros/parsers/parserDifferenceQuotient.pl @@ -25,7 +25,7 @@ =head1 DESCRIPTION argument. The third argument is optional and the default value 0 is used when the third argument is omitted. -=head1 USAGE +=head1 SYNOPSIS simplify (f(x+dx)-f(x)) / dx for f(x)=x^2 diff --git a/macros/parsers/parserFormulaUpToConstant.pl b/macros/parsers/parserFormulaUpToConstant.pl index b984604187..059960332f 100644 --- a/macros/parsers/parserFormulaUpToConstant.pl +++ b/macros/parsers/parserFormulaUpToConstant.pl @@ -91,45 +91,44 @@ sub Init { main::PG_restricted_eval('sub FormulaUpToConstant {FormulaUpToConstant->new(@_)}'); } -# # Create an instance of a FormulaUpToConstant. If no constant # is supplied, we add C ourselves. -# + sub new { my $self = shift; my $class = ref($self) || $self; - # + # Copy the context (so we can modify it) and # replace the usual Variable object with our own. - # + my $context = (Value::isContext($_[0]) ? shift : $self->context)->copy; $context->{parser}{Variable} = 'FormulaUpToConstant::Variable'; - # + # Create a formula from the user's input. - # + my $f = main::Formula($context, @_); - # + # If it doesn't have a constant already, add one. # (should check that C isn't already in use, and look # up the first free name, but we'll cross our fingers # for now. Could look through the defined variables # to see if there is already an arbitraryConstant # and use that.) - # + unless ($f->{constant}) { $f = $f + "C", $f->{constant} = "C" } - # + # Check that the formula is linear in C. - # + my $n = $f->D($f->{constant}); Value->Error("Your formula isn't linear in the arbitrary constant '%s'", $f->{constant}) unless $n->isConstant; - # + # Make a version with adaptive parameters for use in the # comparison later on. We would like n00*C, but already have $n # copies of C, so remove them. That way, n00 will be 0 when there # are no C's in the student answer during the adaptive comparison. # (Again, should really check that n00 is not in use already) - # + my $n00 = $context->variables->get("n00"); $context->variables->add(n00 => 'Parameter') unless $n00 and $n00->{parameter}; my $n01 = $context->variables->get("n01"); @@ -139,33 +138,30 @@ sub new { return bless $f, $class; } -################################################## -# # Remember that compare implements the overloaded perl <=> operator, # and $a <=> $b is -1 when $a < $b, 0 when $a == $b and 1 when $a > $b. # In our case, we only care about equality, so we will return 0 when # equal and other numbers to indicate the reason they are not equal # (this can be used by the answer checker to print helpful messages) -# + sub compare { my ($l, $r) = @_; my $self = $l; my $context = $self->context; $r = Value::makeValue($r, context => $context) unless Value::isValue($r); - # + # Not equal if the student value is constant or has no + C - # + return 2 if !Value::isFormula($r); return 3 if !defined($r->{constant}); - # + # If constants aren't the same, substitute the professor's in the student answer. - # + $r = $r->substitute($r->{constant} => $l->{constant}) unless $r->{constant} eq $l->{constant}; $r->context($context) unless $r->context == $context; - # # Compare with adaptive parameters to see if $l + n00 C = $r for some n0. - # + my $adapt = $l->adapt; my $equal = ($adapt == $r); $self->{adapt} = $self->{adapt}->inherit($adapt); # save the adapted value's flags @@ -173,25 +169,23 @@ sub compare { $self->{adapt}{test_adapt} = $adapt->{test_adapt}; $_[1]->{test_values} = $r->{test_values}; # save these in student answer for diagnostics return -1 unless $equal; - # + # Check that n00 is non-zero (i.e., there is a multiple of C in the student answer) # (remember: return value of 0 is equal, and non-zero is unequal) - # + return (abs($context->variables->get("n00")->{value}) < $context->flag("zeroLevelTol") ? 1 : 0); } -# # Return the {adapt} formula with test points adjusted -# + sub adapt { my $self = shift; return $self->adjustInherit($self->{adapt}); } -# # Inherit from the main FormulaUpToConstant, but # adjust the test points to include the constants -# + sub adjustInherit { my $self = shift; my $f = shift->inherit($self); @@ -209,10 +203,9 @@ sub adjustInherit { return $f; } -# # Insert dummy values for the constants for the test points # (These are supposed to be +C, so the value shouldn't matter?) -# + sub addConstants { my $self = shift; my $points = shift; @@ -237,23 +230,18 @@ sub addConstants { return $Points; } -################################################## -# # Here we override part of the answer comparison # routines in order to be able to generate # helpful error messages for students when # they leave off the + C. -# -# # Show hints by default -# + sub cmp_defaults { ((shift)->SUPER::cmp_defaults, showHints => 1, showLinearityHints => 1) } -# # Provide diagnostics based on the adapted function used to check # the student's answer -# + sub cmp_diagnostics { my $self = shift; my $adapt = $self->inherit($self->{adapt}); @@ -262,10 +250,9 @@ sub cmp_diagnostics { $adapt->SUPER::cmp_diagnostics(@_); } -# # Make it possible to graph single-variable formulas by setting # the arbitrary constants to 0 first. -# + sub cmp_graph { my $self = shift; my $diagnostics = shift; @@ -282,9 +269,8 @@ sub cmp_graph { $self->SUPER::cmp_graph($diagnostics, [ $F1, $F2 ]); } -# # Add useful messages, if the author requested them -# + sub cmp_postprocess { my $self = shift; my $ans = shift; @@ -310,46 +296,39 @@ sub cmp_postprocess { if $result == -1 && $self->getFlag("showLinearityHints") && !$student->D($student->{constant})->isConstant; } -# # Don't perform equivalence check -# + sub cmp_postfilter { my $self = shift; return shift; } -################################################## -# # Get the name of the constant -# + sub constant { (shift)->{constant} } -# # Remove the constant and return a Formula object -# + sub removeConstant { my $self = shift; return $self->adjustInherit(main::Formula($self->substitute($self->{constant} => 0))->reduce); } -# # Override the differentiation so that we always return # a Formula, not a FormulaUpToConstant (we don't want to # add the C in again). -# + sub D { my $self = shift; $self->removeConstant->D(@_); } -###################################################################### -# # This class replaces the Parser::Variable class, and its job # is to look for new constants that aren't in the context, # and add them in. This allows students to use ANY constant # they want, and a different one from the professor. We check # that the student only used ONE arbitrary constant, however. -# + package FormulaUpToConstant::Variable; our @ISA = ('Parser::Variable'); @@ -360,28 +339,28 @@ sub new { my $variables = $equation->{context}{variables}; my ($name, $ref) = @_; my $def = $variables->{$name}; - # + # If the variable is not already in the context, add it # and mark it as an arbitrary constant (for later reference) - # + if (!defined($def) && length($name) eq 1) { $equation->{context}->variables->add($name => 'Real'); $equation->{context}->variables->set($name => { arbitraryConstant => 1 }); $def = $variables->{$name}; } - # + # If the variable is an arbitrary constant # Error if we already have a constant and it's not this one. # Save the constant so we can check with it later. - # + if ($def && $def->{arbitraryConstant}) { $equation->Error(["Your formula shouldn't have two arbitrary constants"], $ref) if $equation->{constant} and $name ne $equation->{constant}; $equation->{constant} = $name; } - # + # Do the usual Variable stuff. - # + $self->SUPER::new($equation, $name, $ref); } diff --git a/macros/parsers/parserFormulaWithUnits.pl b/macros/parsers/parserFormulaWithUnits.pl index 550ba2f0ea..a5029f4431 100644 --- a/macros/parsers/parserFormulaWithUnits.pl +++ b/macros/parsers/parserFormulaWithUnits.pl @@ -13,7 +13,7 @@ =head1 DESCRIPTION to generate a FormulaWithUnits object, and then call its cmp() method to get an answer checker for your formula with units. -=head1 USAGE +=head1 SYNOPSIS ANS(FormulaWithUnits("3x+1 ft")->cmp); ANS(FormulaWithUnits("$a*x+1 ft")->cmp); @@ -49,6 +49,10 @@ =head1 USAGE Note: English pluralization is suprisingly hard, so WeBWorK will make no attempt to display a grammerically correct result. +=head1 SEE ALSO + +There is now a context for handling units: L + =cut loadMacros('MathObjects.pl'); @@ -61,9 +65,10 @@ =head1 USAGE our %known_units = %Units::known_units; sub _parserFormulaWithUnits_init { -# We make copies of these hashes here because these copies will be unique to # the problem. The hashes in Units are shared between problems. We pass -# the hashes for these local copies to the NumberWithUnits package to use -# for all of its stuff. + # We make copies of these hashes here because these copies will be unique to + # the problem. The hashes in Units are shared between problems. We pass + # the hashes for these local copies to the NumberWithUnits package to use + # for all of its stuff. Parser::Legacy::ObjectWithUnits::initializeUnits(\%fundamental_units, \%known_units); diff --git a/macros/parsers/parserLinearRelation.pl b/macros/parsers/parserLinearRelation.pl index 8e19b30c52..d41051a9cd 100644 --- a/macros/parsers/parserLinearRelation.pl +++ b/macros/parsers/parserLinearRelation.pl @@ -1,6 +1,4 @@ -=encoding utf8 - =head1 NAME contextLinearRelation.pl - Implement linear relations. @@ -78,10 +76,7 @@ =head1 DESCRIPTION sub _parserLinearRelation_init { LinearRelation::Init() }; # don't reload this file -################################################## -# # Initialize the contexts and make the creator function. -# package LinearRelation; our @ISA = qw(Value::Formula); @@ -224,10 +219,9 @@ sub new { return bless $plane, $class; } -# # If the vectors are zero, check if true or false # If the vectors are non-zero, check if the equations are multiples of each other. -# + sub compare { my ($self, $l, $r) = Value::checkOpOrder(@_); $l = LinearRelation->new($l) unless ref($l) eq ref($self); @@ -235,9 +229,8 @@ sub compare { my ($lN, $ld, $ltype, $lrev) = ($l->{N}, $l->{d}, $l->{tree}{def}{kind}, $l->{tree}{def}{reverse}); my ($rN, $rd, $rtype, $rrev) = ($r->{N}, $r->{d}, $r->{tree}{def}{kind}, $r->{tree}{def}{reverse}); - # # Outright true or false relations have no type yet, so give them one - # + my $zero = 0 * $lN; if (!$ltype) { $ltype = $l->check_at($zero) ? 'eq' : 'ne'; @@ -246,21 +239,18 @@ sub compare { $rtype = $r->check_at($zero) ? 'eq' : 'ne'; } - # # Reverse inequalities to favor lt, le over gt, ge - # + ($lN, $ld, $ltype) = (-$lN, -$ld, $lrev) if $lrev; ($rN, $rd, $rtype) = (-$rN, -$rd, $rrev) if $rrev; - # # First, check if the type of inequality is the same. # Then check if the dividing (hyper)plane is the right one. - # + return 1 unless $ltype eq $rtype; - # # Are both 0? - # + if ($lN == $zero && $rN == $zero) { my $ltruth = $l->check_at($zero); my $rtruth = $r->check_at($zero); @@ -283,9 +273,8 @@ sub compare { ignoreInfinity => 0, # report infinity as an error ) } -# # Only compare two relations -# + sub typeMatch { my ($self, $other, $ans) = @_; return ref($other) && $other->type eq 'Relation' unless ref($self); @@ -333,10 +322,8 @@ sub isConstant { return $self->SUPER::isConstant; } -# # We subclass BOP::equality so that we can assign a type using _check and # override the _eval method for relation operators -# package LinearRelation::inequality; our @ISA = qw(Parser::BOP::equality); @@ -354,11 +341,9 @@ sub _eval { return $context->Package("Real")->new($context, &{ $self->{def}{eval} }(@_) ? 1 : 0); } -# # We use a special formula object to check if the formula is a # LinearRelation or not, and return the proper class. This allows # lists of linear relations, for example. -# package LinearRelation::formula; our @ISA = ('Value::Formula'); diff --git a/macros/parsers/parserMultiAnswer.pl b/macros/parsers/parserMultiAnswer.pl index 3ea98fe958..65ce546e8f 100644 --- a/macros/parsers/parserMultiAnswer.pl +++ b/macros/parsers/parserMultiAnswer.pl @@ -1,11 +1,11 @@ +# Note: documentation is at the bottom of the file + loadMacros('MathObjects.pl', 'PGbasicmacros.pl'); sub _parserMultiAnswer_init { main::PG_restricted_eval('sub MultiAnswer {parser::MultiAnswer->new(@_)}'); } -################################################## - package parser::MultiAnswer; our @ISA = qw(Value); @@ -60,9 +60,8 @@ sub new { }, $class; } -# # Set flags to be passed to individual answer checkers -# + sub setCmpFlags { my ($self, $cmp_number, %flags) = @_; die "Answer $cmp_number is not defined." unless defined($self->{cmp}[ $cmp_number - 1 ]); @@ -70,11 +69,10 @@ sub setCmpFlags { return $self; } -# # Creates an answer checker (or array of same) to be passed # to ANS() or NAMED_ANS(). Any parameters are passed to # the individual answer checkers. -# + sub cmp { my ($self, %options) = @_; @@ -128,12 +126,9 @@ sub cmp { return @cmp; } -###################################################################### - -# # Get the answer checker used for when all the answers are treated # as a single result. -# + sub single_cmp { my $self = shift; my @correct; @@ -159,14 +154,13 @@ sub single_cmp { return $ans; } -# # Check the answers when they are treated as a single result. -# + # First, call individual answer checkers to get any type-check errors # Then perform the user's checker routine # Finally collect the individual answers and errors and combine # them for the single result. -# + sub single_check { my $self = shift; my $ans = shift; @@ -239,21 +233,17 @@ sub single_check { return $ans; } -# # Return a given string or a default if it is empty or not defined -# + sub check_string { my $s = shift; $s = shift unless defined($s) && $s =~ m/\S/ && $s ne '{\rm }'; return $s; } -###################################################################### - -# # Answer checker to use for individual entries when singleResult # is not in effect. -# + sub entry_cmp { my $self = shift; my $i = shift; @@ -269,11 +259,10 @@ sub entry_cmp { return $ans; } -# # Call the correct answer's checker to check for syntax and type errors. # If this is the last one, perform the user's checker routine as well # Return the individual answer (our answer hash is discarded). -# + sub entry_check { my $self = shift; my $ans = shift; @@ -291,17 +280,14 @@ sub entry_check { return $ANS; } -###################################################################### - -# # Collect together the correct and student answers, and call the # user's checker routine. -# + # If any of the answers produced errors or the types don't match # don't call the user's routine. # Otherwise, call it, and if there was an error, report that. # Set the individual scores based on the result from the user's routine. -# + sub perform_check { my $self = shift; my $rh_ans = shift; @@ -343,12 +329,9 @@ sub perform_check { return; } -###################################################################### - -# # The user's checker can call setMessage(n,message) to set the error message # for the n-th answer blank. -# + sub setMessage { my ($self, $i, $message) = @_; die "Answer $i is not defined." unless defined($self->{ans}[ $i - 1 ]); @@ -364,13 +347,10 @@ sub addMessage { push(@{ $self->{single_ans_messages} }, $message); } -###################################################################### - -# # Produce the name for a named answer blank. # (When the singleResult option is true, use the standard name for the first # one, and create the prefixed names for the rest.) -# + sub ANS_NAME { my $self = shift; my $i = shift; @@ -384,19 +364,17 @@ sub ANS_NAME { return $self->{answerNames}{$i}; } -# # Record an answer-blank name (when using extensions) -# + sub NEW_NAME { my $self = shift; main::RECORD_FORM_LABEL(shift); } -# # Produce an answer rule for the next item in the list, # taking care to use names or extensions as needed # by the settings of the MultiAnswer. -# + sub ans_rule { my $self = shift; my $size = shift || 20; @@ -421,11 +399,10 @@ sub ans_rule { } } -# # Do the same, but for answer arrays, which are generated by the # Value objects automatically sized to suit their data. # Reset the correct_ans once the array is made -# + sub ans_array { my $self = shift; my $size = shift || 5; @@ -456,8 +433,6 @@ sub ans_array { return $HTML; } -###################################################################### - 1; =head1 NAME diff --git a/macros/parsers/parserNumberWithUnits.pl b/macros/parsers/parserNumberWithUnits.pl index b49619c288..354a2442b4 100644 --- a/macros/parsers/parserNumberWithUnits.pl +++ b/macros/parsers/parserNumberWithUnits.pl @@ -47,6 +47,10 @@ =head1 DESCRIPTION Note: English pluralization is suprisingly hard, so WeBWorK will make no attempt to display a grammerically correct result. +=head1 SEE ALSO + +There is now a context for handling units: L + =cut loadMacros('MathObjects.pl'); @@ -55,9 +59,9 @@ =head1 DESCRIPTION our %known_units = %Units::known_units; sub _parserNumberWithUnits_init { -# We make copies of these hashes here because these copies will be unique to # the problem. The hashes in Units are shared between problems. We pass -# the hashes for these local copies to the NumberWithUnits package to use -# for all of its stuff. + # We make copies of these hashes here because these copies will be unique to # the problem. + # The hashes in Units are shared between problems. We pass the hashes for these local copies + # to the NumberWithUnits package to use for all of its stuff. Parser::Legacy::ObjectWithUnits::initializeUnits(\%fundamental_units, \%known_units); # main::PG_restricted_eval('sub NumberWithUnits {Parser::Legacy::NumberWithUnits->new(@_)}'); diff --git a/macros/parsers/parserOneOf.pl b/macros/parsers/parserOneOf.pl index 35ae6bc822..e5d0027361 100644 --- a/macros/parsers/parserOneOf.pl +++ b/macros/parsers/parserOneOf.pl @@ -63,25 +63,21 @@ =head1 DESCRIPTION sub _parserOneOf_init { parser::OneOf::Init() } -###################################################################### - package parser::OneOf; our @ISA = ('Value::List'); my $SEPARATOR = ", "; # default separator my $OR = " or "; # default "or" word -# # Define the OneOf() creator function -# + sub Init { main::PG_restricted_eval('sub OneOf {parser::OneOf->new(@_)}'); } -# # Use Compute() to handle each of the entries so correct_ans will be set # for each entry -# + sub new { my $self = shift; my @params = (@_); @@ -89,18 +85,16 @@ sub new { return $self->SUPER::new(@params); } -# # Return the type of the first entry (usually these will all be the same) -# + sub type { my $self = shift; $self->{data}[0]->type; } -# # Try to match against all the entries, and if any one of them matches, # go with it. -# + sub typeMatch { my $self = shift; my $other = shift; @@ -109,9 +103,8 @@ sub typeMatch { return 0; } -# # Return the class for the first entry -# + sub cmp_class { my $self = shift; return $self->{cmp_class} if defined($self->{cmp_class}); @@ -119,28 +112,25 @@ sub cmp_class { return $x->{cmp_class} || $x->cmp_class(); } -# # Use the standard cmp_equal, not the list version, since # this acts as a single item not a list. -# + sub cmp_equal { Value::cmp_equal(@_); } -# # Check if the student value equals one of the ones in the correct-answer list # and return the result of that comparison if it is correct. # (FIXME: should this check all and return the highest score?) -# + sub cmp_compare { my ($self, $other, $ans) = @_; foreach $x (@{ $self->{data} }) { my $result = $x->cmp_compare($other, $ans); return $result if $result } return 0; } -# # Produce the correct answer by combining correct answers of the originals. -# + sub correct_ans { my $self = shift; my $sep = $self->getFlag("separator", $SEPARATOR); @@ -148,9 +138,8 @@ sub correct_ans { Value::preformat($self->format("correct_ans", $sep, $or)); } -# # Produce the string version by making a comma separated list with " or " for the last comma -# + sub string { my $self = shift; my $sep = $self->getFlag("separator", $SEPARATOR); @@ -158,9 +147,8 @@ sub string { $self->format("string", $sep, $or); } -# # Produce the TeX version by making a comma separated list with " or " for the last comma -# + sub TeX { my $self = shift; my $sep = $self->getFlag("tex_separator", "\\hbox{$SEPARATOR}"); @@ -168,11 +156,10 @@ sub TeX { $self->format("TeX", $sep, $or); } -# # Produce a list of entries separated by $sep with $or as the final separator. # The entries are converted using the given $method of the entry. # If there is a format (or tex_format) flag, use that to format the list instead. -# + sub format { my $self = shift; my $method = shift; @@ -191,10 +178,9 @@ sub format { return join($sep, @c) . $or . $last; } -# # Make a list containing a formula object rather than a # formula returning a list. -# + sub formula { my $self = shift; my $class = ref($self) || $self; diff --git a/macros/parsers/parserParametricLine.pl b/macros/parsers/parserParametricLine.pl index 1fcf062b8c..6c879a5e82 100644 --- a/macros/parsers/parserParametricLine.pl +++ b/macros/parsers/parserParametricLine.pl @@ -43,9 +43,8 @@ =head1 DESCRIPTION sub _parserParametricLine_init { ParametricLine::Init() }; # don't reload this file -# # Define the subclass of Formula -# + package ParametricLine; our @ISA = qw(Value::Formula); @@ -96,16 +95,10 @@ sub new { return bless $line, $class; } -=head2 $lhs == $rhs - - # - # Two parametric lines are equal if they have - # parallel direction vectors and either the same - # points or the vector between the points is - # parallel to the (common) direction vector. - # - -=cut +# Two parametric lines are equal if they have +# parallel direction vectors and either the same +# points or the vector between the points is +# parallel to the (common) direction vector. sub compare { my ($self, $l, $r) = Value::checkOpOrderWithPromote(@_); @@ -125,9 +118,8 @@ sub compare { ignoreInfinity => 0, # report infinity as an error ) } -# # Report some errors that were stopped by the showEqualErrors=>0 above. -# + sub cmp_postprocess { my $self = shift; my $ans = shift; diff --git a/macros/parsers/parserWordCompletion.pl b/macros/parsers/parserWordCompletion.pl index 6bcf3cca25..5dc04c102f 100644 --- a/macros/parsers/parserWordCompletion.pl +++ b/macros/parsers/parserWordCompletion.pl @@ -1,3 +1,5 @@ +# Note: documentation is at the end of the file + loadMacros('MathObjects.pl'); sub _parserWordCompletion_init { @@ -144,7 +146,7 @@ sub new { =head1 NAME -parserWordCompletion.pl +parserWordCompletion.pl - provide a popup with list of allowable answers. =head1 DESCRIPTION diff --git a/macros/ui/PGchoicemacros.pl b/macros/ui/PGchoicemacros.pl index d5846486dd..0b1073cd9b 100644 --- a/macros/ui/PGchoicemacros.pl +++ b/macros/ui/PGchoicemacros.pl @@ -1,3 +1,4 @@ +# Note: Should we deprecate this? =head1 NAME @@ -68,6 +69,11 @@ =head1 DESCRIPTION =back +=head1 SEE ALSO + +Much of the functionality can also be recreated with newer macros: L, +L, L, L + =cut BEGIN { strict->import; } @@ -75,23 +81,13 @@ =head1 DESCRIPTION loadMacros('PGauxiliaryFunctions.pl'); package main; - -# ^function _PGchoicemacros_init - -sub _PGchoicemacros_init { -} +sub _PGchoicemacros_init { } =head1 MACROS -=cut - -################################################################################ +=head2 new_match_list -=head2 Match lists - -=over - -=item new_match_list +Usage: $ml = new_match_list(); @@ -117,14 +113,7 @@ sub new_match_list { new Match(random(1, 2000, 1), \&std_print_q, \&std_print_a); } -=back - - -=head2 Select lists - -=over - -=item new_select_list +=head2 new_select_list $sl = new_select_list(); @@ -153,7 +142,9 @@ sub new_select_list { new Select(random(1, 2000, 1), \&std_print_q, \&std_print_a); } -=item C +=head2 new_pop_up_select_list + +Usage: $sl = new_pop_up_select_list(); @@ -173,17 +164,7 @@ sub new_pop_up_select_list { new Select(random(1, 2000, 1), \&pop_up_list_print_q, \&std_print_a); } -=back - -=cut - -################################################################################ - -=head2 Multiple choice questions - -=over - -=item C +=head2 new_multiple_choice $mc = new_multiple_choice(); @@ -206,7 +187,7 @@ sub new_multiple_choice { new Multiple(random(1, 2000, 1), \&std_print_q, \&radio_print_a); } -=item C +=head2 new_checkbox_multiple_choice $mc = new_checkbox_multiple_choice(); @@ -226,13 +207,7 @@ sub new_checkbox_multiple_choice { new Multiple(random(1, 2000, 1), \&std_print_q, \&checkbox_print_a); } -=back - -=head2 Question printing subroutines - -=over - -=item C +=head2 std_print_q C<$list> can be a matching list, a select list, or a multiple choice list @@ -282,7 +257,7 @@ sub std_print_q { } -=item C +=head2 pop_up_list_print_q $sl->rf_print_q(~~&pop_up_list_print_q); $sl->ra_pop_up_list([T => 'True', F => 'False']); @@ -339,7 +314,7 @@ sub pop_up_list_print_q { } -=item C +=head2 quest_first_pop_up_list_print_q $sl->rf_print_q(~~&quest_first_pop_up_list_print_q); $sl->ra_pop_up_list([T => 'True', F => 'False']); @@ -394,7 +369,7 @@ sub quest_first_pop_up_list_print_q { } -=item C +=head2 ans_in_middle_pop_up_list_print_q $sl->rf_print_q(~~&ans_in_middle_pop_up_list_print_q); $sl->ra_pop_up_list([T => 'True', F => 'False']); @@ -450,7 +425,7 @@ sub ans_in_middle_pop_up_list_print_q { } -=item C +=head2 units_list_print_q A simple popup question printer. No question text is printed, instead the pop_up_list contents only are printed as a popup menu. @@ -474,17 +449,7 @@ sub units_list_print_q { $out; } -=back - -=cut - -################################################################################ - -=head2 Answer printing subroutines - -=over - -=item C +=head2 std_print_a # $list can be a matching list, a select list, or a multiple choice list $list->rf_print_a(~~&std_print_a); @@ -527,7 +492,7 @@ sub std_print_a { } -=item C +=head2 radio_print_a C<$list> can be a matching list, a select list, or a multiple choice list @@ -583,7 +548,7 @@ sub radio_print_a { } -=item C +=head2 checkbox_print_a C<$list> can be a matching list, a select list, or a multiple choice list @@ -636,22 +601,15 @@ sub checkbox_print_a { } -=back - -=cut - -################################################################################ - -=head2 Legacy macros +=head1 Legacy macros [DEPRECATED] These are maintained for backward compatibility. They can still be useful in constructing non-standard lists that don't fit the various list objects. In general the using the list objects is likely to give better results and is preferred. -=over -=item [DEPRECATED] qa() +=head2 qa() [DEPRECATED] qa($questions, $answers, @new_qa); @@ -661,7 +619,7 @@ =head2 Legacy macros =cut # ^function qa [DEPRECATED] -# + sub qa { my ($questionsRef, $answersRef, @questANDanswer) = @_; while (@questANDanswer) { @@ -671,7 +629,7 @@ sub qa { } } -=item [DEPRECATED] invert() +=head2 invert() [DEPRECATED] @b = invert(@a); @@ -691,7 +649,7 @@ sub invert { @out; } -=item [DEPRECATED] NchooseK() +=head2 NchooseK() [DEPRECATED] @b = NchooseK($N, $K); @@ -709,12 +667,16 @@ sub NchooseK { return @return; } -=item [DEPRECATED] shuffle() +=head2 shuffle() [DEPRECATED] @b = shuffle($i); Returns the integers from 0 to $i-1 in random order. +Note: this can be reproduced with the function + + @b = random_subset($n, 0..$n-1); + =cut # ^function shuffle [DEPRECATED] @@ -726,7 +688,7 @@ sub shuffle { return @return; } -=item [DEPRECATED] match_questions_list() +=head2 match_questions_list() [DEPRECATED] =cut @@ -759,7 +721,7 @@ sub match_questions_list { $out; } -=item [DEPRECATED] match_questions_list_varbox() +=head2 [DEPRECATED] match_questions_list_varbox() =cut @@ -792,8 +754,4 @@ sub match_questions_list_varbox { $out; } -=back - -=cut - 1; diff --git a/macros/ui/PGinfo.pl b/macros/ui/PGinfo.pl index b05888eb1a..276d3c33ce 100644 --- a/macros/ui/PGinfo.pl +++ b/macros/ui/PGinfo.pl @@ -1,16 +1,16 @@ =head1 NAME -PGinfo.pl - -Provides macros for determining the values of the current context in which the problem +PGinfo.pl - Provides macros for determining the values of the current context in which the problem is being written. =cut loadMacros("MathObjects.pl"); -=head2 listVariables +=head1 FUNCTIONS + +=head2 listVariables Usage: listVariables(); @@ -30,7 +30,7 @@ sub listVariables { listContextFlags(); } -=head3 listFormVariables() +=head2 listFormVariables Called by C to print out the input form variables. @@ -43,7 +43,7 @@ sub listFormVariables { } -=head3 listEnvironmentVariables() +=head2 listEnvironmentVariables Called by C to print out the environment variables (in %envir). @@ -54,7 +54,7 @@ sub listEnvironmentVariables { TEXT(pretty_print(\%envir)); } -=head3 listContextFlags() +=head2 listContextFlags Called by listVariables to print out context flags for Math Objects. @@ -65,7 +65,7 @@ sub listContextFlags { TEXT(pretty_print($context)); } -=head2 listContext() +=head2 listContext Usage: listContext(Context()) @@ -84,12 +84,11 @@ sub listContext { # include } } -=head2 pp() +=head2 pp Usage: pp(Hash ); pp(Object); - Prints out the contents of Hash or the instance variables of Object =cut diff --git a/macros/ui/alignedChoice.pl b/macros/ui/alignedChoice.pl index 4d19cdccd3..854b5ddc9e 100644 --- a/macros/ui/alignedChoice.pl +++ b/macros/ui/alignedChoice.pl @@ -1,3 +1,5 @@ +# Note: this should be deprecated. Can be recreated with niceTables + loadMacros('PGchoicemacros.pl', 'unionUtils.pl', 'choiceUtils.pl',); sub _alignedChoice_init { }; # don't reload this file diff --git a/macros/ui/choiceUtils.pl b/macros/ui/choiceUtils.pl index ab84fc0b77..d22ecffbc6 100644 --- a/macros/ui/choiceUtils.pl +++ b/macros/ui/choiceUtils.pl @@ -1,3 +1,5 @@ +# Note: this should be deprecated. Can be recreated with niceTables + sub _choiceUtils_init { }; # don't reload this file # diff --git a/macros/ui/niceTables.pl b/macros/ui/niceTables.pl index a8220b8443..0df8308a63 100644 --- a/macros/ui/niceTables.pl +++ b/macros/ui/niceTables.pl @@ -1,7 +1,12 @@ -=head1 niceTables.pl +=head1 NAME -Subroutines for creating tables that: +niceTables.pl - Subroutines for creating tables that are accessible, more uniform +styling, can include CSS or LaTeX. + +=head1 DESCRIPTION + +This macro allows tables that can be made that =over @@ -24,7 +29,7 @@ =head1 niceTables.pl relation between content cells within a column or within a row. If the answer is no in both cases, it is likely a case for C. -=head2 Description + Command for a typical table: @@ -93,7 +98,7 @@ =head3 All output formats If it is a decimal, it will be interpreted as a portion of the available width. C for a column that expands to fill (see C below), -and will have left-aligned paragraphs +and will have left-aligned paragraphs C<|> for a vertical rule (n adjacent pipes make one rule that is n times as thick) diff --git a/macros/ui/quickMatrixEntry.pl b/macros/ui/quickMatrixEntry.pl index 7f855cf870..a8b7f02238 100644 --- a/macros/ui/quickMatrixEntry.pl +++ b/macros/ui/quickMatrixEntry.pl @@ -1,3 +1,5 @@ +# Note: documentation at the bottom of the file + loadMacros('MathObjects.pl'); sub _quickMatrixEntry_init { diff --git a/macros/ui/source.pl b/macros/ui/source.pl index 85dcd6e36e..282bd754eb 100644 --- a/macros/ui/source.pl +++ b/macros/ui/source.pl @@ -1,3 +1,5 @@ +# Note: this probably no longer works using CGI unless specifically set up. Deprecate? + if ($displayMode =~ m/HTML/ && !defined($_slides_loaded)) { TEXT('

' . '