You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(58) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(53) |
Feb
(56) |
Mar
|
Apr
|
May
(30) |
Jun
(78) |
Jul
(121) |
Aug
(155) |
Sep
(77) |
Oct
(61) |
Nov
(45) |
Dec
(94) |
2006 |
Jan
(116) |
Feb
(33) |
Mar
(11) |
Apr
(23) |
May
(60) |
Jun
(89) |
Jul
(130) |
Aug
(109) |
Sep
(124) |
Oct
(63) |
Nov
(82) |
Dec
(45) |
2007 |
Jan
(31) |
Feb
(35) |
Mar
(123) |
Apr
(36) |
May
(18) |
Jun
(134) |
Jul
(133) |
Aug
(241) |
Sep
(126) |
Oct
(31) |
Nov
(15) |
Dec
(5) |
2008 |
Jan
(11) |
Feb
(6) |
Mar
(16) |
Apr
(29) |
May
(43) |
Jun
(149) |
Jul
(27) |
Aug
(29) |
Sep
(37) |
Oct
(20) |
Nov
(4) |
Dec
(6) |
2009 |
Jan
(34) |
Feb
(30) |
Mar
(16) |
Apr
(6) |
May
(1) |
Jun
(32) |
Jul
(22) |
Aug
(7) |
Sep
(18) |
Oct
(50) |
Nov
(22) |
Dec
(8) |
2010 |
Jan
(17) |
Feb
(15) |
Mar
(10) |
Apr
(9) |
May
(67) |
Jun
(30) |
Jul
|
Aug
|
Sep
(2) |
Oct
|
Nov
(1) |
Dec
|
From: dpvc v. a. <we...@ma...> - 2007-09-29 00:05:18
|
Log Message: ----------- Allow inequalities to include infinity and -infinity (so you can enter -inf < x < inf to get all reals). Modified Files: -------------- pg/macros: contextInequalities.pl Revision Data ------------- Index: contextInequalities.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextInequalities.pl,v retrieving revision 1.12 retrieving revision 1.13 diff -Lmacros/contextInequalities.pl -Lmacros/contextInequalities.pl -u -r1.12 -r1.13 --- macros/contextInequalities.pl +++ macros/contextInequalities.pl @@ -155,7 +155,7 @@ ($self->{varPos},$self->{numPos}) = ($self->{lop}->class eq 'Variable' || $self->{lop}{isInequality} ? ('lop','rop') : ('rop','lop')); my ($v,$n) = ($self->{$self->{varPos}},$self->{$self->{numPos}}); - if ($n->isNumber && $n->{isConstant}) { + if (($n->isNumber || $n->{isInfinite}) && $n->{isConstant}) { if ($v->class eq 'Variable') { $self->{varName} = $v->{name}; delete $self->{equation}{variables}{$v->{name}} if $v->{isNew}; |
From: Matt L. v. a. <we...@ma...> - 2007-09-28 23:44:24
|
Log Message: ----------- Changed DEBUG to 0 Modified Files: -------------- wwmoodle/wwassignment3/moodle/mod/wwassignment: locallib.php Revision Data ------------- Index: locallib.php =================================================================== RCS file: /webwork/cvs/system/wwmoodle/wwassignment3/moodle/mod/wwassignment/locallib.php,v retrieving revision 1.3 retrieving revision 1.4 diff -Lwwassignment3/moodle/mod/wwassignment/locallib.php -Lwwassignment3/moodle/mod/wwassignment/locallib.php -u -r1.3 -r1.4 --- wwassignment3/moodle/mod/wwassignment/locallib.php +++ wwassignment3/moodle/mod/wwassignment/locallib.php @@ -2,7 +2,7 @@ require_once("$CFG->libdir/soap/nusoap.php"); -define(WWASSIGNMENT_DEBUG,1); +define(WWASSIGNMENT_DEBUG,0); ////////////////////////////////////////////////////////////////// //EVENT CREATION AND DELETION @@ -516,4 +516,4 @@ return $this->handler('grade_users_sets',array('courseName' => $webworkcourse, 'userIDs' => $webworkusers, 'setID' => $webworkset)); } }; -?> \ No newline at end of file +?> |
From: dpvc v. a. <we...@ma...> - 2007-09-28 23:32:12
|
Log Message: ----------- Fixed a problem where the context was not properly maintained when intervals are combined. Modified Files: -------------- pg/macros: contextInequalities.pl Revision Data ------------- Index: contextInequalities.pl =================================================================== RCS file: /webwork/cvs/system/pg/macros/contextInequalities.pl,v retrieving revision 1.11 retrieving revision 1.12 diff -Lmacros/contextInequalities.pl -Lmacros/contextInequalities.pl -u -r1.11 -r1.12 --- macros/contextInequalities.pl +++ macros/contextInequalities.pl @@ -669,8 +669,8 @@ if (defined($x)) {$S->{varName} = $x; $S->updateParts} return $S; } - $x = ($self->context->variables->names)[0] unless $x; - $S = bless $S->inContext($context), $self->Package("Inequality".$S->type); + $x = ($context->variables->names)[0] unless $x; + $S = bless $S->inContext($context), $context->Package("Inequality".$S->type); $S->{varName} = $x; $S->{reduceSets} = $S->{"is".$S->Type} = 1; $S->updateParts; return $S; |
From: Sam H. v. a. <we...@ma...> - 2007-09-28 00:41:00
|
Log Message: ----------- added MathObjects examples from webwork2/doc/parser Added Files: ----------- pg/doc/MathObjects/extensions: 1-function.pg 2-function.pg 3-operator.pg 4-list.pg 5-operator.pg 6-precedence.pg 7-context.pg 8-answer.pg pg/doc/MathObjects/macros: Differentiation.pl DifferentiationDefs.pl parserTables.pl parserUtils.pl unionImage.pl unionTables.pl pg/doc/MathObjects/problems: sample01.pg sample02.pg sample03.pg sample04.pg sample05.pg sample06.pg sample07.pg sample08.pg sample09.pg sample10.pg sample11.pg sample12.pg sample13.pg sample14.pg sample15.pg sample16.pg sample17.pg sample18.pg sample19.pg sample20.pg sample21.pg sample22.pg Revision Data ------------- --- /dev/null +++ doc/MathObjects/extensions/2-function.pg @@ -0,0 +1,83 @@ +########################################################## +# +# Example showing how to add a new two-variable function to the Parser +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################### +# +# Use standard numeric mode +# +Context('Numeric'); + +############################################# +# +# Create a "Combinations" function +# + +package MyFunction2; +our @ISA = qw(Parser::Function::numeric2); # this is what makes it R^2 -> R + +sub C { + shift; my ($n,$r) = @_; my $C = 1; + $r = $n-$r if ($r > $n-$r); # find the smaller of the two + for (1..$r) {$C = $C*($n-$_+1)/$_} + return $C +} + +package main; + +# +# Make it work on formulas as well as numbers +# +sub C {Parser::Function->call('C',@_)} + +# +# Add the new functions into the Parser +# + +Context()->functions->add(C => {class => 'MyFunction2'}); + +$x = Formula('x'); + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we have added a new function to the Parser: ${BTT}C(n,r)${ETT}. +(Edit the code to see how this is done). +$PAR +Assuming that ${BTT}${DOLLAR}x = Formula('x')${ETT}, it can be used as follows: +$PAR + +\{ParserTable( + 'Formula("C(x,3)")', + 'C(6,2)', + 'C($x,3)', + 'Formula("C(x,3)")->eval(x=>6)', + '(C($x,2))->eval(x=>6)', + 'Formula("C(x)")', + 'Formula("C(1,2,3)")', + 'C(1)', + 'C(1,2,3)', + )\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/4-list.pg @@ -0,0 +1,106 @@ +########################################################## +# +# Example showing how to add a new list-type object +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# Define our own [n,r] notation for n choose r +# + +package MyChoose; +our @ISA = qw(Parser::List); # subclass of List + +# +# Check that two numbers are given +# +sub _check { + my $self = shift; + $self->{type}{list} = 0; # our result is a single number, not really a list + $self->Error("You need two numbers within '[' and ']'") + if ($self->{type}{length} < 2); + $self->Error("Only two numbers can appear within '[' and ']'") + if ($self->{type}{length} > 2); + my ($n,$r) = @{$self->{coords}}; + $self->Error("The arguments for '[n,r]' must be numbers") + unless ($n->type eq 'Number' && $r->type eq 'Number'); + $self->{type} = $Value::Type{number}; +} + +# +# Compute n choose r +# +sub _eval { + shift; my ($n,$r) = @_; my $C = 1; + $r = $n-$r if ($r > $n-$r); # find the smaller of the two + for (1..$r) {$C = $C*($n-$_+1)/$_} + return $C +} + +# +# Non-standard TeX output +# +sub TeX { + my $self = shift; + return '{'.$self->{coords}[0]->TeX.' \choose '.$self->{coords}[1]->TeX.'}'; +} + +# +# Non-standard perl output +# +sub perl { + my $self = shift; + return '(MyChoose->_eval('.$self->{coords}[0]->perl.','.$self->{coords}[1]->perl.'))'; +} + + +package main; + +########################################################## +# +# Add the new list to the context +# + +Context()->lists->add(Choose => {class => 'MyChoose'}); +Context()->parens->replace('[' => {close => ']', type => 'Choose'}); + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we have added a new list to the Parser: ${BTT}[n,r]${ETT}, +which returns \(n\choose r\). +$PAR + +\{ParserTable( + 'Formula("[x,3]")', + 'Formula("[5,3]")', + 'Formula("[x,3]")->eval(x=>5)', + '$C = Formula("[x,y]"); $C->substitute(x=>5)', + 'Formula("[x,y]")->perlFunction("C"); C(5,3)', + 'Formula("[x,y,3]")', + 'Formula("[x]")', + 'Formula("[x,[y,2]]")', + 'Formula("[x,<1,2>]")', + )\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/7-context.pg @@ -0,0 +1,86 @@ +########################################################## +# +# Example showing how to switch different contexts +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we compare formulas in complex and vector contexts. +Note the difference between how ${BTT}i${ETT} is treated in the two +contexts. Note that 'Number' comprises both real and complex numbers. +$PAR + +Assuming that ${BTT}${DOLLAR}x = Formula('x')${ETT}, it can be used as follows: +$PAR + +END_TEXT + +$x = Formula('x'); + +########################################################## +# +# Use Complex context +# + +Context('Complex'); + +BEGIN_TEXT +\{Title("The Complex context:")\} +$PAR +\{ParserTable( + 'i', + 'Formula("1+3i")', + 'Formula("x+3i")', + '1 + 3*i', + '$x + 3*i', + '$z = tan(2*i)', + 'Formula("sinh(zi)")', + 'Formula("3i+4j-k")', + 'Formula("3i+4j-k")->eval', + '3*i + 4*j - k', +)\} +$PAR$BR +END_TEXT + + +########################################################## +# +# Use Vector context +# + +Context('Vector'); + +BEGIN_TEXT +\{Title("The Vector context:")\} +$PAR +\{ParserTable( + 'i', + 'Formula("1+3i")', + 'Formula("x+3i")', + '1 + 3*i', + '$x + 3*i', + '$z = tan(2*i)', + 'Formula("sinh(zi)")', + 'Formula("3i+4j-k")', + 'Formula("3i+4j-k")->eval', + '3*i + 4*j - k', +)\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/5-operator.pg @@ -0,0 +1,89 @@ +########################################################## +# +# Example of how to implement equalities in the Parser +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# Define our own operator for equality +# + +package Equality; +our @ISA = qw(Parser::BOP); # subclass of Binary OPerator + +# +# Check that the operand types are numbers. +# +sub _check { + my $self = shift; my $name = $self->{bop}; + $self->Error("Only one equality is allowed in an equation") + if ($self->{lop}->class eq 'Equality' || $self->{rop}->class eq 'Equality') ; + $self->Error("Operands of '$name' must be Numbers") unless $self->checkNumbers(); + $self->{type} = Value::Type('Equality',1); # Make it not a number, to get errors with other operations. +} + +# +# Determine if the two sides are equal +# +sub _eval {return ($_[1] == $_[2])? 1: 0} + +package main; + +# +# Add the operator into the current context +# + +$prec = Context()->operators->get(',')->{precedence} + .25; + +Context()->operators->add( + '=' => { + class => 'Equality', + precedence => $prec, # just above comma + associativity => 'left', # computed left to right + type => 'bin', # binary operator + string => '=', # output string for it + perl => '==', # perl string + } +); + + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we have added a new operator to the Parser: ${BTT} a += b${ETT}, for equality. +$PAR + +\{ParserTable( + 'Formula("x + y = 0")', + 'Formula("x + y = 0")->{tree}->class', + 'Formula("x + y = 0")->{tree}{lop}', + 'Formula("x + y = 0")->{tree}{rop}', + 'Formula("x + y = 0")->eval(x=>2,y=>3)', + 'Formula("x + y = 0")->eval(x=>2,y=>-2)', + 'Formula("x + y = 0 = z")', + 'Formula("(x + y = 0) + 5")', + 'Formula("x + y = 0, 3x-y = 4")', # you CAN get a list of equalities + )\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/8-answer.pg @@ -0,0 +1,112 @@ +########################################################## +# +# Example showing an answer checker that uses the parser +# to evaluate the student (and professor's) answers. +# +# This is now obsolete, as the paser's ->cmp method +# can be used to produce an answer checker for any +# of the parser types. +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserUtils.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# Use Vector context +# + +Context('Vector'); + +########################################################## +# +# Make the answer checker +# +sub vector_cmp { + my $v = shift; + die "vector_cmp requires a vector argument" unless defined $v; + my $v = Vector($v); # covert to vector if it isn't already + my $ans = new AnswerEvaluator; + $ans->ans_hash(type => "vector",correct_ans => $v->string, vector=>$v); + $ans->install_evaluator(~~&vector_cmp_check); + return $ans; +} + +sub vector_cmp_check { + my $ans = shift; my $v = $ans->{vector}, + $ans->score(0); # assume failure + my $f = Parser::Formula($ans->{student_ans}); + my $V = Parser::Evaluate($f); + if (defined $V) { + $V = Formula($V) unless Value::isValue($V); # make sure we can call Value methods + $ans->{preview_latex_string} = $f->TeX; + $ans->{preview_text_string} = $f->string; + $ans->{student_ans} = $V->string; + if ($V->type eq 'Vector') { + $ans->score(1) if ($V == $v); # Let the overloaded == do the check + } else { + $ans->{ans_message} = $ans->{error_message} = + "Your answer doesn't seem to be a Vector (it looks like ".Value::showClass($V).")" + unless $inputs_ref->{previewAnswers}; + } + } else { + # + # Student answer evaluation failed. + # Report the error, with formatting, if possible. + # + my $context = Context(); + my $message = $context->{error}{message}; + if ($context->{error}{pos}) { + my $string = $context->{error}{string}; + my ($s,$e) = @{$context->{error}{pos}}; + $message =~ s/; see.*//; # remove the position from the message + $ans->{student_ans} = protectHTML(substr($string,0,$s)) . + '<SPAN CLASS="parsehilight">' . + protectHTML(substr($string,$s,$e-$s)) . + '</SPAN>' . + protectHTML(substr($string,$e)); + } + $ans->{ans_message} = $ans->{error_message} = $message; + } + return $ans; +} + +########################################################## +# +# The problem text +# + +$V = Vector(1,2,3); + +Context()->flags->set(ijk=>0); +Context()->constants->add(a=>1,b=>1,c=>1); + +$ABC = Formula("<a,b,c>"); + +BEGIN_TEXT +Enter the vector \(\{$V->TeX\}\) in any way you like: \{ans_rule(20)\}. +$PAR +You can use either \(\{$ABC->TeX\}\) or \(\{$ABC->ijk\}\) notation,$BR +and can perform vector operations to produce your answer. +$PAR +${BBOLD}Note:${EBOLD} This problem is obsolete. +END_TEXT + +########################################################### +# +# The answer +# + +ANS(vector_cmp($V)); + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/6-precedence.pg @@ -0,0 +1,84 @@ +########################################################## +# +# Example of the non-standard precedences as a possible alternative +# that makes it possible to write "sin 2x" and get "sin(2x)" +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# Use standard precedences for multiplication +# + +Context()->usePrecedence("Standard"); + +$standard = ParserTable( + 'Formula("sin 2xy/3")', + 'Formula("sin 2x y/3")', + 'Formula("sin 2x y / 3")', + 'Formula("sin 2x+5")', + 'Formula("sin x(x+1)")', + 'Formula("sin x (x+1)")', + 'Formula("1/2xy")', + 'Formula("1/2 xy")', + 'Formula("1/2x y")', + 'Formula("sin^2 x")', + 'Formula("sin^(-1) x")', + 'Formula("x^2x")', +); + +Context()->usePrecedence("Non-Standard"); + +$nonstandard = ParserTable( + 'Formula("sin 2xy/3")', + 'Formula("sin 2x y/3")', + 'Formula("sin 2x y / 3")', + 'Formula("sin 2x+5")', + 'Formula("sin x(x+1)")', + 'Formula("sin x (x+1)")', + 'Formula("1/2xy")', + 'Formula("1/2 xy")', + 'Formula("1/2x y")', + 'Formula("sin^2 x")', + 'Formula("sin^(-1) x")', + 'Formula("x^2x")', +); + + + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we compare the standard and non-standard precedences for +multiplication. +$PAR + +\{Title("The Non-Standard precedences:")\} +$PAR +$nonstandard +$PAR$BR + +\{Title("The Standard precedences:")\} +$PAR +$standard + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/3-operator.pg @@ -0,0 +1,113 @@ +########################################################## +# +# Example showing how to add new operators to the Parser +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# Define our own binary operator +# + +package MyOperator; +our @ISA = qw(Parser::BOP); # subclass of Binary OPerator + +# +# Check that the operand types are numbers. +# +sub _check { + my $self = shift; my $name = $self->{bop}; + return if $self->checkNumbers(); + $self->Error("Operands of '$name' must be Numbers"); +} + +# +# Compute the value of n choose r. +# +sub _eval { + shift; my ($n,$r) = @_; my $C = 1; + $r = $n-$r if ($r > $n-$r); # find the smaller of the two + for (1..$r) {$C = $C*($n-$_+1)/$_} + return $C +} + +# +# Non-standard TeX output +# +sub TeX { + my $self = shift; + return '{'.$self->{lop}->TeX.' \choose '.$self->{rop}->TeX.'}'; +} + +# +# Non-standard perl output +# +sub perl { + my $self = shift; + return '(MyOperator->_eval('.$self->{lop}->perl.','.$self->{rop}->perl.'))'; +} + +package main; + +########################################################## +# +# Add the operator into the current context +# + +$prec = Context()->operators->get('+')->{precedence} - .25; + +Context()->operators->add( + '#' => { + class => 'MyOperator', + precedence => $prec, # just below addition + associativity => 'left', # computed left to right + type => 'bin', # binary operator + string => ' # ', # output string for it + TeX => '\mathop{\#}', # TeX version (overridden above, but just an example) + } +); + + +$CHOOSE = MODES(TeX => '\#', HTML => '#'); + + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we have added a new operator to the Parser: ${BTT}n $CHOOSE r${ETT}, +which returns \(n\choose r\). +$PAR + +\{ParserTable( + 'Formula("x # y")', + 'Formula("x+1 # 5")', + 'Formula("x # 5")->eval(x=>7)', + 'Formula("(x#5)+(x#4)")', + 'Formula("x#5+x#4")', + 'Formula("x # y")', + 'Formula("x # y")->substitute(x=>5)', + 'Formula("x # y")->eval(x=>5,y=>2)', + 'Formula("x # y")->perlFunction(~~'C~~'); C(5,2)', + 'Formula("1 # <x,3>")', + )\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/extensions/1-function.pg @@ -0,0 +1,83 @@ +########################################################## +# +# Example showing how to add a new single-variable function to the Parser +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserTables.pl", +); + +TEXT(beginproblem()); + +########################################################### +# +# Use standard numeric mode +# +Context('Numeric'); + +############################################# +# +# Create a 'log2' function to the Parser for log base 2 +# + +package MyFunction1; +our @ISA = qw(Parser::Function::numeric); # this is what makes it R -> R + +sub log2 { + shift; my $x = shift; + return CORE::log($x)/CORE::log(2); +} + +package main; + +# +# Make it work on formulas as well as numbers +# +sub log2 {Parser::Function->call('log2',@_)} + +# +# Add the new functions into the Parser +# + +Context()->functions->add( + log2 => {class => 'MyFunction1', TeX => '\log_2'}, # fancier TeX output +); + +$x = Formula('x'); + +########################################################### +# +# The problem text +# +BEGIN_TEXT +$BEGIN_ONE_COLUMN + +In this problem, we have added a new function to the Parser: ${BTT}log2(x)${ETT}. +(Edit the code to see how this is done.) +$PAR +Assuming that ${BTT}${DOLLAR}x = Formula('x')${ETT}, it can be used as follows: +$PAR + +\{ParserTable( + 'Formula("log2(x)")', + 'log2(8)', + 'log2($x+1)', + 'Formula("log2(x)")->eval(x=>16)', + '(log2($x))->eval(x=>16)', + 'Formula("log2()")', + 'Formula("log2(1,x)")', + 'log2()', + 'log2(1,3)', + )\} + +$END_ONE_COLUMN +END_TEXT + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/macros/parserTables.pl @@ -0,0 +1,87 @@ +loadMacros("parserUtils.pl"); + +############################################# +# +# For Parser example tables: +# + +$BTT = MODES(TeX=>'{\tt ', Latex2HTML => $bHTML.'<TT>'.$eHTML, HTML => '<TT>'); +$ETT = MODES(TeX=>'}', Latex2HTML => $bHTML.'</TT>'.$eHTML, HTML => '</TT>'); + +$BC = MODES( + TeX=>'{\small\it ', + Latex2HTML => $bHTML.'<SMALL><I>'.$eHTML, + HTML => '<SMALL><I>' +); +$EC = MODES( + TeX=>'}', + Latex2HTML => $bHTML.'</I></SMALL>'.$eHTML, + HTML => '</I></SMALL>' +); + +$LT = MODES(TeX => "<", Latex2HTML => "<", HTML => '<'); +$GT = MODES(TeX => ">", Latex2HTML => ">", HTML => '>'); + +$TEX = MODES(TeX => '{\TeX}', HTML => 'TeX', HTML_dpng => '\(\bf\TeX\)'); + +@rowOptions = ( + indent => 0, + separation => 0, + align => 'LEFT" NOWRAP="1', # alignment hack to get NOWRAP +); + +sub ParserRow { + my $f = shift; my $t = ''; + Context()->clearError; + my ($s,$err) = PG_restricted_eval($f); + if (defined $s) { + my $ss = $s; + if (ref($s) && \&{$s->string}) { + $t = '\('.$s->TeX.'\)'; + $s = $s->string; + } elsif ($s !~ m/^[a-z]+$/i) { + $t = '\('.Formula($s)->TeX.'\)'; + $s = Formula($s)->string; + } + $s =~ s/</$LT/g; $s =~ s/>/$GT/g; + if (ref($ss) && \&{$ss->class}) { + if ($ss->class eq 'Formula') { + $s .= ' '.$BC.'(Formula returning '.$ss->showType.')'.$EC; + } else { + $s .= ' '.$BC.'('.$ss->class.' object)'.$EC; + } + } + } else { + $s = $BC. (Context()->{error}{message} || $err) . $EC; + $t = ''; + } + $f =~ s/</$LT/g; $f =~ s/>/$GT/g; + if ($displayMode eq 'TeX') { + $f =~ s/\^/\\char`\\^/g; $s =~ s/\^/\\char`\\^/g; + $f =~ s/#/\\#/g; $s =~ s/#/\\#/g; + } + my $row = Row([$BTT.$f.$ETT,$BTT.$s.$ETT,$t],@rowOptions); + $row =~ s/\$/\${DOLLAR}/g; + return $row; +} + +sub ParserTable { + my $table = + BeginTable(border=>1, padding=>20). + Row([$BBOLD."Perl Code".$EBOLD, + $BBOLD."Result".$EBOLD, + $BBOLD.$TEX.' version'.$EBOLD],@rowOptions); + foreach my $f (@_) {$table .= ParserRow($f)} + $table .= EndTable(); + return $table; +} + +sub Title { + my $title = shift; + + MODES( + TeX => "\\par\\centerline{\\bf $title}\\par\\nobreak\n", + Latex2HTML => $bHTML.'<CENTER><H2>'.$title.'</H2></CENTER>'.$eHTML, + HTML => '<CENTER><H2>'.$title.'</H2></CENTER>' + ); +} --- /dev/null +++ doc/MathObjects/macros/Differentiation.pl @@ -0,0 +1,20 @@ +# +# Example of how to add new functionality to the Parser. +# +# Here we load new methods for the Parser object classes. Note, however, +# that these are PERSISTANT when used with webwork2 (mod_perl), and so we +# need to take care not to load them more than once. We look for the +# variable $Parser::Differentiation::loaded, which is defined in the +# differentiation package, in order to tell. +# +# DifferentiationDefs.pl is really just a copy of the +# Parser::Differentiation.pm file, and you really could just preload the +# latter instead by uncommenting the 'use Parser::Differentiation' line at +# the bottom of Parser.pm. (This file is really just a sample). The way +# it's done here will load it the first time it gets used, then will keep +# it around, so not much overhead even this way. +# + +loadMacros("DifferentiationDefs.pl") unless $Parser::Differentiation::loaded; + +1; --- /dev/null +++ doc/MathObjects/macros/DifferentiationDefs.pl @@ -0,0 +1,635 @@ +# +# Extend differentiation to multiple variables +# Check differentiation for complex functions +# Do derivatives for norm and unit. +# +# Make shortcuts for getting numbers 1, 2, and sqrt, etc. +# + +################################################## +# +# Differentiate the formula in terms of the given variable +# +sub Parser::D { + my $self = shift; my $x = shift; + if (!defined($x)) { + my @vars = keys(%{$self->{variables}}); + my $n = scalar(@vars); + if ($n == 0) { + return $self->new('0') if $self->{isNumber}; + $x = 'x'; + } else { + $self->Error("You must specify a variable to differentiate by") unless $n ==1; + $x = $vars[0]; + } + } else { + return $self->new('0') unless defined $self->{variables}{$x}; + } + return $self->new($self->{tree}->D($x)); +} + +sub Item::D { + my $self = shift; + my $type = ref($self); $type =~ s/.*:://; + $self->Error("Differentiation for '$type' is not implemented",$self->{ref}); +} + + +######################################################################### + +sub Parser::BOP::comma::D {Item::D(shift)} +sub Parser::BOP::union::D {Item::D(shift)} + +sub Parser::BOP::add::D { + my $self = shift; my $x = shift; + $self = Parser::BOP->new( + $self->{equation},$self->{bop}, + $self->{lop}->D($x),$self->{rop}->D($x) + ); + return $self->reduce; +} + + +sub Parser::BOP::subtract::D { + my $self = shift; my $x = shift; + $self = Parser::BOP->new( + $self->{equation},$self->{bop}, + $self->{lop}->D($x),$self->{rop}->D($x) + ); + return $self->reduce; +} + +sub Parser::BOP::multiply::D { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + $self = + Parser::BOP->new($equation,'+', + Parser::BOP->new($equation,$self->{bop}, + $self->{lop}->D($x),$self->{rop}->copy($equation)), + Parser::BOP->new($equation,$self->{bop}, + $self->{lop}->copy($equation),$self->{rop}->D($x)) + ); + return $self->reduce; +} + +sub Parser::BOP::divide::D { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + $self = + Parser::BOP->new($equation,$self->{bop}, + Parser::BOP->new($equation,'-', + Parser::BOP->new($equation,'*', + $self->{lop}->D($x),$self->{rop}->copy($equation)), + Parser::BOP->new($equation,'*', + $self->{lop}->copy($equation),$self->{rop}->D($x)) + ), + Parser::BOP->new($equation,'^', + $self->{rop},Parser::Number->new($equation,2) + ) + ); + return $self->reduce; +} + +sub Parser::BOP::power::D { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + my $vars = $self->{rop}->getVariables; + if (defined($vars->{$x})) { + $vars = $self->{lop}->getVariables; + if (defined($vars->{$x})) { + $self = + Parser::Function->new($equation,'exp', + [Parser::BOP->new($equation,'*',$self->{rop}->copy($equation), + Parser::Function->new($equation,'log',[$self->{lop}->copy($equation)],0))]); + return $self->D($x); + } + $self = Parser::BOP->new($equation,'*', + Parser::Function->new($equation,'log',[$self->{lop}->copy($equation)],0), + Parser::BOP->new($equation,'*', + $self->copy($equation),$self->{rop}->D($x)) + ); + } else { + $self = + Parser::BOP->new($equation,'*', + Parser::BOP->new($equation,'*', + $self->{rop}->copy($equation), + Parser::BOP->new($equation,$self->{bop}, + $self->{lop}->copy($equation), + Parser::BOP->new($equation,'-', + $self->{rop}->copy($equation), + Parser::Number->new($equation,1) + ) + ) + ), + $self->{lop}->D($x) + ); + } + return $self->reduce; +} + +sub Parser::BOP::cross::D {Item::D(shift)} +sub Parser::BOP::dot::D {Item::D(shift)} +sub Parser::BOP::underscore::D {Item::D(shift)} + +######################################################################### + +sub Parser::UOP::plus::D { + my $self = shift; my $x = shift; + return $self->{op}->D($x) +} + +sub Parser::UOP::minus::D { + my $self = shift; my $x = shift; + $self = Parser::UOP->new($self->{equation},'u-',$self->{op}->D($x)); + return $self->reduce; +} + +sub Parser::UOP::factorial::D {Item::D(shift)} + +######################################################################### + +sub Parser::Function::D { + my $self = shift; + $self->Error("Differentiation of '$self->{name}' not implemented",$self->{ref}); +} + +sub Parser::Function::D_chain { + my $self = shift; my $x = $self->{params}[0]; + my $name = "D_" . $self->{name}; + $self = Parser::BOP->new($self->{equation},'*',$self->$name($x->copy),$x->D(shift)); + return $self->reduce; +} + +############################# + +sub Parser::Function::trig::D {Parser::Function::D_chain(@_)} + +sub Parser::Function::trig::D_sin { + my $self = shift; my $x = shift; + return Parser::Function->new($self->{equation},'cos',[$x]); +} + +sub Parser::Function::trig::D_cos { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::Function->new($equation,'sin',[$x]) + ); +} + +sub Parser::Function::trig::D_tan { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'^', + Parser::Function->new($equation,'sec',[$x]), + Parser::Number->new($equation,2) + ); +} + +sub Parser::Function::trig::D_cot { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::BOP->new($equation,'^', + Parser::Function->new($equation,'csc',[$x]), + Parser::Number->new($equation,2) + ) + ); +} + +sub Parser::Function::trig::D_sec { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'*', + Parser::Function->new($equation,'sec',[$x]), + Parser::Function->new($equation,'tan',[$x]) + ); +} + +sub Parser::Function::trig::D_csc { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::BOP->new($equation,'*', + Parser::Function->new($equation,'csc',[$x]), + Parser::Function->new($equation,'cot',[$x]) + ) + ); +} + +sub Parser::Function::trig::D_asin { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::Function->new($equation,'sqrt',[ + Parser::BOP->new($equation,'-', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'^', + $x,Parser::Number->new($equation,2) + ) + )] + ) + ); +} + +sub Parser::Function::trig::D_acos { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::Function->new($equation,'sqrt',[ + Parser::BOP->new($equation,'-', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'^', + $x,Parser::Number->new($equation,2) + ) + )] + ) + ) + ); +} + +sub Parser::Function::trig::D_atan { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'+', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'^', + $x, Parser::Number->new($equation,2) + ) + ) + ); +} + +sub Parser::Function::trig::D_acot { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'+', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'^', + $x, Parser::Number->new($equation,2) + ) + ) + ) + ); +} + +sub Parser::Function::trig::D_asec { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'*', + Parser::Function->new($equation,'abs',[$x]), + Parser::Function->new($equation,'sqrt',[ + Parser::BOP->new($equation,'-', + Parser::BOP->new($equation,'^', + $x, Parser::Number->new($equation,2) + ), + Parser::Number->new($equation,1) + )] + ) + ) + ); +} + +sub Parser::Function::trig::D_acsc { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'*', + Parser::Function->new($equation,'abs',[$x]), + Parser::Function->new($equation,'sqrt',[ + Parser::BOP->new($equation,'-', + Parser::BOP->new($equation,'^', + $x, Parser::Number->new($equation,2) + ), + Parser::Number->new($equation,1) + )] + ) + ) + ) + ); +} + + +############################# + +sub Parser::Function::hyperbolic::D {Parser::Function::D_chain(@_)} + +sub Parser::Function::hyperbolic::D_sinh { + my $self = shift; my $x = shift; + return Parser::Function->new($self->{equation},'cosh',[$x]); +} + +sub Parser::Function::hyperbolic::D_cosh { + my $self = shift; my $x = shift; + return Parser::Function->new($self->{equation},'sinh',[$x]); +} + +sub Parser::Function::hyperbolic::D_tanh { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'^', + Parser::Function->new($equation,'sech',[$x]), + Parser::Number->new($equation,2) + ); +} + +sub Parser::Function::hyperbolic::D_coth { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::BOP->new($equation,'^', + Parser::Function->new($equation,'csch',[$x]), + Parser::Number->new($equation,2) + ) + ); +} + +sub Parser::Function::hyperbolic::D_sech { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::BOP->new($equation,'*', + Parser::Function->new($equation,'sech',[$x]), + Parser::Function->new($equation,'tanh',[$x]) + ) + ); +} + +sub Parser::Function::hyperbolic::D_csch { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::BOP->new($equation,'*', + Parser::Function->new($equation,'csch',[$x]), + Parser::Function->new($equation,'coth',[$x]) + ) + ); +} + +sub Parser::Function::hyperbolic::D_asinh { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::Function->new($equation,'sqrt',[ + Parser::BOP->new($equation,'+', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'^', + $x, Parser::Number->new($equation,2) + ) + )] + ) + ); +} + +sub Parser::Function::hyperbolic::D_acosh { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::Function->new($equation,'sqrt',[ + Parser::BOP->new($equation,'-', + Parser::BOP->new($equation,'^', + $x, Parser::Number->new($equation,2) + ), + Parser::Number->new($equation,1) + )] + ) + ); +} + +sub Parser::Function::hyperbolic::D_atanh { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'-', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'^', + $x, Parser::Number->new($equation,2) + ) + ) + ); +} + +sub Parser::Function::hyperbolic::D_acoth { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'-', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'^', + $x, Parser::Number->new($equation,2) + ) + ) + ); +} + +sub Parser::Function::hyperbolic::D_asech { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'*', + $x, + Parser::Function->new($equation,'sqrt',[ + Parser::BOP->new($equation,'-', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'^', + $x, Parser::Number->new($equation,2) + ) + )] + ) + ) + ) + ); +} + +sub Parser::Function::hyperbolic::D_acsch { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::UOP->new($equation,'u-', + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'*', + Parser::Function->new($equation,'abs',[$x]), + Parser::Function->new($equation,'sqrt',[ + Parser::BOP->new($equation,'+', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'^', + $x, Parser::Number->new($equation,2) + ) + )] + ) + ) + ) + ); +} + + +############################# + +sub Parser::Function::numeric::D {Parser::Function::D_chain(@_)} + +sub Parser::Function::numeric::D_log { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return Parser::BOP->new($equation,'/',Parser::Number->new($equation,1),$x); +} + +sub Parser::Function::numeric::D_log10 { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'*', + Parser::Number->new($equation,CORE::log(10)), $x + ) + ); +} + +sub Parser::Function::numeric::D_exp { + my $self = shift; my $x = shift; + return $self->copy(); +} + +sub Parser::Function::numeric::D_sqrt { + my $self = shift; my $x = shift; + my $equation = $self->{equation}; + return + Parser::BOP->new($equation,'/', + Parser::Number->new($equation,1), + Parser::BOP->new($equation,'*', + Parser::Number->new($equation,2), + $self->copy + ) + ); +} + +sub Parser::Function::numeric::D_abs {Parser::Function::D(@_)} +sub Parser::Function::numeric::D_int {Parser::Function::D(@_)} +sub Parser::Function::numeric::D_sgn {Parser::Function::D(@_)} + +######################################################################### + +sub Parser::List::D { + my $self = shift; my $x = shift; + $self = $self->copy($self->{equation}); + foreach my $f (@{$self->{coords}}) {$f = $f->D($x)} + return $self->reduce; +} + + +sub Parser::List::Interval::D { + my $self = shift; + $self->Error("Can't differentiate intervals",$self->{ref}); +} + +sub Parser::List::AbsoluteValue::D { + my $self = shift; + $self->Error("Can't differentiate absolute values",$self->{ref}); +} + + +######################################################################### + +sub Parser::Number::D {Parser::Number->new(shift->{equation},0)} + +######################################################################### + +sub Parser::Complex::D {Parser::Number->new(shift->{equation},0)} + +######################################################################### + +sub Parser::Constant::D {Parser::Number->new(shift->{equation},0)} + +######################################################################### + +sub Parser::Value::D { + my $self = shift; my $x = shift; my $equation = $self->{equation}; + return Parser::Value->new($equation,$self->{value}->D($x,$equation)); +} + +sub Value::D { + my $self = shift; my $x = shift; my $equation = shift; + return 0 if $self->isComplex; + my @coords = @{$self->{data}}; + foreach my $n (@coords) + {if (ref($n) eq "") {$n = 0} else {$n = $n->D($x,$equation)->data}} + return $self->new([@coords]); +} + +sub Value::List::D { + my $self = shift; my $x = shift; my $equation = shift; + my @coords = @{$self->{data}}; + foreach my $n (@coords) + {if (ref($n) eq "") {$n = 0} else {$n = $n->D($x)}} + return $self->new([@coords]); +} + +sub Value::Interval::D { + shift; shift; my $self = shift; + $self->Error("Can't differentiate intervals",$self->{ref}); +} + +sub Value::Union::D { + shift; shift; my $self = shift; + $self->Error("Can't differentiate unions",$self->{ref}); +} + +######################################################################### + +sub Parser::Variable::D { + my $self = shift; my $x = shift; + my $d = ($self->{name} eq $x)? 1: 0; + return Parser::Number->new($self->{equation},$d); +} + +######################################################################### + +sub Parser::String::D {Parser::Number->new(shift->{equation},0)} + +######################################################################### + +package Parser::Differentiation; +our $loaded = 1; + +######################################################################### + +1; --- /dev/null +++ doc/MathObjects/macros/unionImage.pl @@ -0,0 +1,75 @@ +###################################################################### +# +# A routine to make including images easier to control +# +# Usage: Image(name,options) +# +# where name is the name of an image file or a reference to a +# graphics object (or a reference to a pair of one of these), +# and options are taken from among the following: +# +# size => [w,h] the size of the image in the HTML page +# (default is [150,150]) +# +# tex_size => r the size to use in TeX mode (as a percentage +# of the line width times 10). E.g., 500 is +# half the width, etc. (default is 200.) +# +# link => 0 or 1 whether to include a link to the original +# image (default is 0, unless there are +# two images given) +# +# border => 0 or 1 size of image border in HTML mode +# (defaults to 2 or 1 depending on whether +# there is a link or not) +# +# align => placement vertical alignment for image in HTML mode +# (default is "BOTTOM") +# +# tex_center => 0 or 1 whether to center the image horizontally +# in TeX mode (default is 0) +# +# The image name can be one of a number of different things. It can be +# the name of an image file, or an alias to one produce by the alias() +# command. It can be a graphics object reference created by init_graph(). +# Or it can be a pair of these (in square brackets). The first is the +# image for the HTML file, and the second is the image that it will be +# linked to. +# +# Examples: Image("graph.gif", size => [200,200]); +# Image(["graph.gif","graph-large.gif"]); +# +# The alias() and insertGraph() functions will be called automatically +# when needed. +# +sub Image { + my $image = shift; my $ilink; + my %options = ( + size => [150,150], tex_size => 200, + link => 0, align => "BOTTOM", tex_center => 0, @_); + my ($w,$h) = @{$options{size}}; + my ($ratio,$link) = ($options{tex_size}*(.001),$options{link}); + my ($border,$align) = ($options{border},$options{align}); + my ($tcenter) = $options{tex_center}; + my $HTML; my $TeX; + ($image,$ilink) = @{$image} if (ref($image) eq "ARRAY"); + $image = alias(insertGraph($image)) if (ref($image) eq "WWPlot"); + $image = alias($image) unless ($image =~ m!^/!i); + if ($ilink) { + $ilink = alias(insertGraph($ilink)) if (ref($ilink) eq "WWPlot"); + $ilink = alias($ilink) unless ($ilink =~ m!^/!i); + } else {$ilink = $image} + $border = (($link || $ilink ne $image)? 2: 1) unless defined($border); + $HTML = '<IMG SRC="'.$image.'" WIDTH="'.$w. + '" HEIGHT="'.$h.'" BORDER="'.$border.'" ALIGN="'.$align.'">'; + $HTML = '<A HREF="'.$ilink.'">'.$HTML.'</A>' if $link or $ilink ne $image; + $TeX = '\includegraphics[width='.$ratio.'\linewidth]{'.$image.'}'; + $TeX = '\centerline{'.$TeX.'}' if $tcenter; + MODES( + TeX => $TeX."\n", + Latex2HTML => $bHTML.$HTML.$eHTML, + HTML => $HTML + ); +} + +1; --- /dev/null +++ doc/MathObjects/macros/unionTables.pl @@ -0,0 +1,253 @@ +###################################################################### +## +## Functions for creating tables of various kinds +## +## ColumnTable() Creates a two-column display in HTML, +## but only one column in TeX. +## +## ColumnMatchTable() Does a side-by-side match table +## +## BeginTable() Begin a borderless HTML table +## Row() Create a row in the table +## AlignedRow() Create a row with alignment in each column +## TableSpace() Insert extra vertical space in the table +## EndTable() End the table +## + +###################################################################### +# +# Make a two-column table in HTML and Latex2HTML modes +# +# Usage: ColumnTable(col1,col2,[options]) +# +# Options can be taken from: +# +# indent => n the width to indent the first column +# (default is 0) +# +# separation => n the width of the separating gutter +# (default is 50) +# +# valign => type set the vertical alignment +# (default is "MIDDLE") +# +sub ColumnTable { + my $col1 = shift; my $col2 = shift; + my %options = (indent => 0, separation => 50, valign => "MIDDLE", @_); + my ($ind,$sep) = ($options{"indent"},$options{"separation"}); + my $valign = $options{"valign"}; + + my ($bhtml,$ehtml) = ('\begin{rawhtml}','\end{rawhtml}'); + ($bhtml,$ehtml) = ('','') unless ($displayMode eq "Latex2HTML"); + + my $HTMLtable = qq { + $bhtml<TABLE BORDER="0"><TR VALIGN="$valign"> + <TD WIDTH="$ind"> </TD><TD>$ehtml + $col1 + $bhtml</TD><TD WIDTH="$sep"> </TD><TD>$ehtml + $col2 + $bhtml</TD></TR></TABLE>$ehtml + }; + + MODES( + TeX => '\par\medskip\hbox{\qquad\vtop{'. + '\advance\hsize by -3em '.$col1.'}}'. + '\medskip\hbox{\qquad\vtop{'. + '\advance\hsize by -3em '.$col2.'}}\medskip', + Latex2HTML => $HTMLtable, + HTML => $HTMLtable + ); +} + +# +# Use columns for a match-list output +# +# Usage: ColumnMatchTable($ml,options) +# +# where $ml is a math list reference and options are those +# allowed for ColumnTable above. +# +sub ColumnMatchTable { + my $ml = shift; + + ColumnTable($ml->print_q,$ml->print_a,@_); +} + + +# +# Command for tables with no borders. +# +# Usage: BeginTable(options); +# +# Options are taken from: +# +# border => n value for BORDER attribute (default 0) +# spacing => n value for CELLSPACING attribute (default 0) +# padding => n value for CELLPADDING attribute (default 0) +# tex_spacing => dimen value for spacing between columns in TeX +# (e.g, tex_spacing => 2em) (default 1em) +# tex_border => dimen value for left- and right border in TeX (0pt) +# center => 0 or 1 center table or not (default 1) +# +sub BeginTable { + my %options = (border => 0, padding => 0, spacing => 0, center => 1, + tex_spacing => "1em", tex_border => "0pt", @_); + my ($bd,$pd,$sp) = ($options{border},$options{padding},$options{spacing}); + my ($tsp,$tbd) = ($options{tex_spacing},$options{tex_border}); + my ($center,$tcenter) = (' ALIGN="CENTER"','\centerline'); + ($center,$tcenter) = ('','') if (!$options{center}); + my $table = + qq{<TABLE BORDER="$bd" CELLPADDING="$pd" CELLSPACING="$sp"$center>}; + + MODES( + TeX => '\par\medskip'.$tcenter.'{\kern '.$tbd. + '\vbox{\halign{#\hfil&&\kern '.$tsp.' #\hfil', + Latex2HTML => $bHTML.$table.$eHTML."\n", + HTML => $table."\n" + ); +} + +# +# Usage: EndTable(options) +# +# where options are taken from: +# +# tex_border => dimen extra vertical space in TeX mode (default 0pt) +# +sub EndTable { + my %options = (tex_border => "0pt", @_); + my $tbd = $options{tex_border}; + MODES( + TeX => '\cr}}\kern '.$tbd.'}\medskip'."\n", + Latex2HTML => $bHTML.'</TABLE>'.$eHTML."\n", + HTML => '</TABLE>'."\n" + ); +} + +# +# Creates a row in the table +# +# Usage: Row([item1,item2,...],options); +# +# Each item appears as a separate entry in the table. +# +# Options control how the row is displayed: +# +# indent => num Specifies size of blank column on the left +# (default: indent => 0) +# +# separation => num Specifies separation of columns +# (default: spearation => 30) +# +# align => "type" Specifies alignment of initial column +# (default: align => "LEFT") +# +# valign => "type" Specified vertical alignment of row +# (default: valign => "MIDDLE") +# +sub Row { + my $rowref = shift; my @row = @{$rowref}; + my %options = ( + indent => 0, separation => 30, + align => "LEFT", valign => "MIDDLE", + @_ + ); + my ($cind,$csep) = ($options{indent},$options{separation}); + my ($align,$valign) = ($options{align},$options{valign}); + my $sep = '<TD WIDTH="'.$csep.'"> </TD>'; $sep = '' if ($csep < 1); + my $ind = '<TD WIDTH="'.$cind.'"> </TD>'; $ind = '' if ($cind < 1); + my $fill = ''; + $fill = '\hfil' if (uc($align) eq "CENTER"); + $fill = '\hfill' if (uc($align) eq "RIGHT"); + + MODES( + TeX => "\\cr\n". $fill . join('& ',@row), + Latex2HTML => + $bHTML."<TR VALIGN=\"$valign\">$ind<TD ALIGN=\"$align\">".$eHTML . + join($bHTML."</TD>$sep<TD>".$eHTML,@row) . + $bHTML.'</TD></TR>'.$eHTML."\n", + HTML => "<TR VALIGN=\"$valign\">$ind<TD ALIGN=\"$align\">" . + join("</TD>$sep<TD>",@row) . '</TD></TR>'."\n" + ); +} + +# +# AlignedRow([item1,item2,...],options); +# +# Options control how the row is displayed: +# +# indent => num Specifies size of blank column on the left +# (default: indent => 0) +# +# separation => num Specifies separation of columns +# (default: spearation => 30) +# +# align => "type" Specifies alignment of all columns +# (default: align => "CENTER") +# +# valign => "type" Specified vertical alignment of row +# (default: valign => "MIDDLE") +# +sub AlignedRow { + my $rowref = shift; my @row = @{$rowref}; + my %options = ( + indent => 0, separation => 30, + align => "CENTER", valign => "MIDDLE", + @_ + ); + my ($cind,$csep) = ($options{indent},$options{separation}); + my ($align,$valign) = ($options{align},$options{valign}); + my $sep = '<TD WIDTH="'.$csep.'"> </TD>'; $sep = '' if ($csep < 1); + my $ind = '<TD WIDTH="'.$cind.'"> </TD>'; $ind = '' if ($cind < 1); + my $fill = ''; + $fill = '\hfil ' if (uc($align) eq "CENTER"); + $fill = '\hfill ' if (uc($align) eq "RIGHT"); + + MODES( + TeX => "\\cr\n". $fill . join('&'.$fill,@row), + Latex2HTML => + $bHTML."<TR VALIGN=\"$valign\">$ind<TD ALIGN=\"$align\">".$eHTML . + join($bHTML."</TD>$sep<TD ALIGN=\"$align\">".$eHTML,@row) . + $bHTML.'</TD></TR>'.$eHTML."\n", + HTML => "<TR VALIGN=\"$valign\">$ind<TD ALIGN=\"$align\">" . + join("</TD>$sep<TD ALIGN=\"$align\">",@row) . '</TD></TR>'."\n" + ); +} + +# +# Add extra space between rows of a table +# +# Usage: TableSpace(pixels,points) +# +# where pixels is the number of pixels of space in HTML mode and +# points is the number of points to use in TeX mode. +# +sub TableSpace { + my $rsep = shift; + my $tsep = shift; + $rsep = $tsep if (defined($tsep) && $main::displayMode eq "TeX"); + return "" if ($rsep < 1); + MODES( + TeX => '\vadjust{\kern '.$rsep.'pt}' . "\n", + Latex2HTML => + $bHTML.'<TR><TD HEIGHT="'.$rsep.'"><!></TD></TR>'.$eHTML."\n", + HTML => '<TR><TD HEIGHT="'.$rsep.'"></TD></TR>'."\n", + ); +} + +# +# A horizontal rule within a table. (Could have been a variable, +# but all the other table commands are subroutines, so kept it +# one to be consistent.) +# +sub TableLine { + MODES( + TeX => '\vadjust{\kern2pt\hrule\kern2pt}', + Latex2HTML => $bHTML. + '<TR><TD COLSPAN="10"><HR NOSHADE SIZE="1"></TD></TR>'. + $eHTML."\n", + HTML =>'<TR><TD COLSPAN="10"><HR NOSHADE SIZE="1"></TD></TR>'."\n" + ); +} + +1; --- /dev/null +++ doc/MathObjects/macros/parserUtils.pl @@ -0,0 +1,61 @@ +loadMacros( + "unionImage.pl", + "unionTables.pl", +); + +$bHTML = '\begin{rawhtml}'; +$eHTML = '\end{rawhtml}'; + +# HTML(htmlcode) +# HTML(htmlcode,texcode) +# +# Insert $html in HTML mode or \begin{rawhtml}$html\end{rawhtml} in +# Latex2HTML mode. In TeX mode, insert nothing for the first form, and +# $tex for the second form. +# +sub HTML { + my ($html,$tex) = @_; + return('') unless (defined($html) && $html ne ''); + $tex = '' unless (defined($tex)); + MODES(TeX => $tex, Latex2HTML => $bHTML.$html.$eHTML, HTML => $html); +} + +# +# Begin and end <TT> mode +# +$BTT = HTML('<TT>','\texttt{'); +$ETT = HTML('</TT>','}'); + +# +# Begin and end <SMALL> mode +# +$BSMALL = HTML('<SMALL>','{\small '); +$ESMALL = HTML('</SMALL>','}'); + +# +# Block quotes +# +$BBLOCKQUOTE = HTML('<BLOCKQUOTE>','\hskip3em '); +$EBLOCKQUOTE = HTML('</BLOCKQUOTE>'); + +# +# Smart-quotes in TeX mode, regular quotes in HTML mode +# +$LQ = MODES(TeX => '``', Latex2HTML => '"', HTML => '"'); +$RQ = MODES(TeX => "''", Latex2HTML => '"', HTML => '"'); + +# +# make sure all characters are displayed +# +sub protectHTML { + my $string = shift; + $string =~ s/&/\&/g; + $string =~ s/</\</g; + $string =~ s/>/\>/g; + $string; +} + +sub _parserUtils_init {} + +1; + --- /dev/null +++ doc/MathObjects/problems/sample12.pg @@ -0,0 +1,62 @@ +########################################################## +# +# Example showing how to use the built-in answer checker for parsed values. +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserUtils.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# The setup +# + +Context("Interval"); + +$a = non_zero_random(-5,5,1); +$f = Formula("(x^2+1)/(x-$a)")->reduce; +$R = Union("(-inf,$a) U ($a,inf)"); + +########################################################## +# +# The problem text +# + +Context()->texStrings; +BEGIN_TEXT + +Suppose \(\displaystyle f(x) = $f\). +$PAR +Then \(f\) is defined on the region \{ans_rule(30)\}. +$PAR +${BCENTER} +${BSMALL} +Several intervals can be combined using the +set union symbol, ${LQ}${BTT}U${ETT}${RQ}.$BR +Use ${LQ}${BTT}infinity${ETT}${RQ} for ${LQ}\(\infty\)${RQ} and +${LQ}${BTT}-infinity${ETT}${RQ} for ${LQ}\(-\infty\)${RQ}. +${ESMALL} +${ECENTER} + +END_TEXT +Context()->normalStrings; + +########################################################### +# +# The answer +# + +ANS($R->cmp); +$showPartialCorrectAnswers=1; + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/problems/sample19.pg @@ -0,0 +1,67 @@ +########################################################### +# +# Example showing how to use the Parser's function +# answer checker. +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserUtils.pl", +); + +TEXT(beginproblem()); + +########################################################### +# +# The setup +# +Context('Interval')->variables->add(a=>'Real'); +$x = Formula('x'); $a = Formula('a'); + +$f = log($x-$a); +$I = Formula("(-infinity,a]"); + +########################################################### +# +# The problem text +# + +Context()->texStrings; +BEGIN_TEXT + +Suppose \(f(x) = $f\). +$PAR +Then \(f\) is undefined for \(x\) in the interval(s) +\{ans_rule(20)\}. +$PAR +${BCENTER} +${BSMALL} +To enter more than one interval, separate them by commas.$BR +Use ${LQ}${BTT}infinity${ETT}${RQ} for ${LQ}\(\infty\)${RQ} and +${LQ}${BTT}-infinity${ETT}${RQ} for ${LQ}\(-\infty\)${RQ}.$BR +Enter ${LQ}${BTT}NONE${ETT}${RQ} if the function is always defined. +${ESMALL} +${ECENTER} + +END_TEXT +Context()->normalStrings; + +########################################################### +# +# The answers +# +ANS(List($I)->cmp( + list_type => 'a list of intervals', # override these names to avoid + entry_type => "an interval", # 'formula returning ...' messages +)); +Context()->variables->remove('x'); # error if 'x' is used in answer + +$showPartialCorrectAnswers = 1; + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/problems/sample16.pg @@ -0,0 +1,63 @@ +########################################################### +# +# Example showing how to use the Parser's function +# answer checker. +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "Differentiation.pl", +); + +TEXT(beginproblem()); + +########################################################### +# +# The setup +# +Context('Numeric'); +$x = Formula('x'); # used to construct formulas below. + +# +# Define a function and its derivative and make them pretty +# +$a = random(1,8,1); +$b = random(-8,8,1); +$c = random(-8,8,1); + +$f = ($a*$x**2 + $b*$x + $c) -> reduce; +$df = $f->D('x'); + +$x = random(-8,8,1); + +########################################################### +# +# The problem text +# + +Context()->texStrings; +BEGIN_TEXT + +Suppose \(f(x) = $f\). +$PAR +Then \(f'(x)=\) \{ans_rule(20)\},$BR +and \(f'($x)=\) \{ans_rule(20)\}. + +END_TEXT +Context()->normalStrings; + +########################################################### +# +# The answers +# +ANS($df->cmp); +ANS($df->eval(x=>$x)->cmp); +$showPartialCorrectAnswers = 1; + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/problems/sample15.pg @@ -0,0 +1,59 @@ +########################################################## +# +# Example showing how to use the built-in answer checker for parsed values. +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros.pl", + "Parser.pl", + "parserUtils.pl", +); + +TEXT(beginproblem()); + +########################################################## +# +# The setup +# + +Context("Numeric"); + +$a = random(1,5,1); +$f = Formula("(x^2-$a)/(x^2+$a)"); + +########################################################## +# +# The problem text +# + +Context()->texStrings; +BEGIN_TEXT + +Suppose \(\displaystyle f(x) = $f\). +$PAR +Then \(f\) is defined for all \(x\) except for \{ans_rule(30)\}. +$PAR +${BCENTER} +${BSMALL} +To enter more than one value, separate them by commas.$BR +Enter ${LQ}${BTT}NONE${ETT}${RQ} if there are no such values. +${ESMALL} +${ECENTER} + +END_TEXT +Context()->normalStrings; + +########################################################### +# +# The answer +# + +ANS(List("NONE")->cmp); +$showPartialCorrectAnswers = 1; + +########################################################### + +ENDDOCUMENT(); # This should be the last executable line in the problem. --- /dev/null +++ doc/MathObjects/problems/sample14.pg @@ -0,0 +1,59 @@ +########################################################## +# +# Example showing how to use the built-in answer checker for parsed values. +# + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGbasicmacros.pl", + "PGanswermacros... [truncated message content] |
From: Sam H. v. a. <we...@ma...> - 2007-09-28 00:33:32
|
Update of /webwork/cvs/system/pg/doc/MathObjects/macros In directory devel.webwork.rochester.edu:/tmp/cvs-serv70195/macros Log Message: Directory /webwork/cvs/system/pg/doc/MathObjects/macros added to the repository |
From: Sam H. v. a. <we...@ma...> - 2007-09-28 00:33:32
|
Update of /webwork/cvs/system/pg/doc/MathObjects/extensions In directory devel.webwork.rochester.edu:/tmp/cvs-serv70195/extensions Log Message: Directory /webwork/cvs/system/pg/doc/MathObjects/extensions added to the repository |
From: Sam H. v. a. <we...@ma...> - 2007-09-28 00:33:32
|
Update of /webwork/cvs/system/pg/doc/MathObjects/problems In directory devel.webwork.rochester.edu:/tmp/cvs-serv70195/problems Log Message: Directory /webwork/cvs/system/pg/doc/MathObjects/problems added to the repository |
From: Sam H. v. a. <we...@ma...> - 2007-09-28 00:30:55
|
Log Message: ----------- converted basic mathobjects docs to POD Added Files: ----------- pg/doc/MathObjects: MathObjectsAnswerCheckers.pod README.pod UsingMathObjects.pod Revision Data ------------- --- /dev/null +++ doc/MathObjects/UsingMathObjects.pod @@ -0,0 +1,393 @@ +=head1 Using MathObjects + +To use MathObjects in your own problems, you need to load the +"MathObjects.pl" macro file: + + loadMacros("Parser.pl"); + +which defines the commands you need to interact with MathObjects. +Once you have done that, you can call the MathObjects functions to create +formulas for you. The main call is Formula(), which takes a string and +returns a parsed version of the string. For example: + + $f = Formula("x^2 + 3x + 1"); + +will set $f to a reference to the parsed version of the formula. + +=head2 Working With Formulas + +A formula has a number of methods that you can call. These include: + +=over + +=item $f->eval(x=>5) + +Evaluate the formula when x is 5. +If $f has more variables than that, then +you must provide additional values, as in +$f->eval(x=>3,y=>1/2); + +=item $f->reduce + +Tries to remove redundent items from your +formula. For example, Formula("1x+0") returns "x". +Reduce tries to factor out negatives and do +some other adjustments as well. (There still +needs to be more work done on this. What it does +is correct, but not always smart, and there need +to be many more situations covered.) All the +reduction rules can be individually enabled +or disabled using the Context()->reduction->set() +method, but the documentation for the various +rules is not yet ready. + +=item $f->substitute(x=>5) + +Replace x by the value 5 throughout (you may want +to reduce the result afterword, as this is not +done automatically). Note that you can replace a +variable by another formula, if you wish. To make +this easier, substitute will apply Formula() to +any string values automatically. E.g., + Formula("x-1")->substitute(x=>"y") +returns "y-1" as a formula. + +=item $f->string + +returns a string representation of the formula +(should be equivalent to the original, though not +necessarily equal to it). + +=item $f->TeX + +returns a LaTeX representation of the formula. +You can use this in BEGIN_TEXT...END_TEXT blocks +as follows: + + BEGIN_TEXT + Suppose \(f(x) = \{$f->TeX}\). ... + END_TEXT + +=item $f->perl + +returns a representation of the formula that could +be evaluated by perl's eval() function. + +=item $f->perlFunction + +returns a perl code block that can be called to +evaluate the function. For example: + + $f = Formula('x^2 + 3')->perlFunction; + $y = &$f(5); + +will assign the value 28 to $y. +You can also pass a function name to perlFunction +to get a named function to call: + + Formula('x^2 + 3')->perlFunction('f'); + $y = f(5); + +If the formula involves more than one variable, +then the paramaters should be given in +alphabetical order. + + Formula('x^2 + y')->perlFunction('f'); + $z = f(5,3); # $z is 28. + +Alternatively, you can tell the order for the +parameters: + + Formula('x^2 + y')->perlFunction('f',['y','x']); + $z = f(5,3); $ now $z is 14. + +=back + +=head2 Combining Formulas + +There is a second way to create formulas. Once you have a formula, you can +create additional formulas simply by using perls' built-in operations and +functions, which have been overloaded to handle formulas. For example, + + $x = Formula('x'); + $f = 3*x**2 + 2*$x - 1; + +makes $f be a formula, and is equivalent to having done + + $f = Formula("3x^2 + 2x - 1"); + +This can be very convenient, but also has some pitfalls. First, you +need to include '*' for multiplication, since perl doesn't do implied +multiplication, and you must remember to use '**' not '^'. (If you use '^' +on a formula, the parser will remind you to use '**'.) Second, the +precedences of the operators in perl are fixed, and so changes you make to +the precedence table for the parser are not reflected in formulas produced +in this way. (The reason '^' is not overloaded to do exponentiation is +that the precedence of '^' is wrong for that in perl, and can't be +changed.) As long as you leave the default precedences, however, things +should work as you expect. + +Note that the standard functions, like sin, cos, etc, are overloaded to +generate appropriate formulas when their values are formulas. For example, + + $x = Formula('x'); + $f = cos(3*$x + 1); + +produces the same result as $f = Formula("cos(3x+1)"); and you can then go +on to output its TeX form, etc. + +=head2 Special Syntax + +This parser has support for some things that are missing from the current +one, like absolute values. You can say |1+x| rather than abs(1+x) +(though both are allowed), and even |1 - |x|| works. + +Also, you can use sin^2(x) (or even sin^2 x) to get (sin(x))^2. + +Finally, you can use sin^-1(x) to get arcsin(x). + +There is an experimental set of operator precedences that make it possible +to write sin 2x + 3 and get sin(2x) + 3. See examples/7-precedence.pg +for some details. + +=head2 The Formula Types + +The parser understands a wide range of data types, including real and +complex numbers, points, vectors, matrices, arbitrary lists, intervals, +unions of intervals, and predefined words. Each has a syntax for use +within formulas, as described below: + + numbers the usual form: 153, 233.5, -2.456E-3, etc. + + complex a + b i where a and b are numbers: 1+i, -5i, 6-7i, etc. + + infinitites the words 'infinity' or '-infinity' (or several + equivalents). + + point (a,b,c) where a, b and c are real or complex numbers. + any number of coordinates are allowed. Eg, (1,2), + (1,0,0,0), (-1,2,-3). Points are promoted to vectors + automatically, when necessary. + + vector <a,b,c> or a i + b j + c k (when used in vector context). + As with points, vectors can have any number of + coordinates. For example, <1,0,0>, <-1,3>, <x,1-x>, etc. + + matrix [[a11,...,a1n],...[am1,...amn]], i.e., use [..] around + each row, and around the matrix itself. The elements + are separated by commas (not spaces). e.g, + [[1,2],[3,4]] (a 2x2 matrix) + [1,2] (a 1x2 matrix, really a vector) + [[1],[2]] (a 2x1 matrix, ie. column vector) + Points and vectors are promoted to matrices when + appropriate. Vectors are converted to column vectors + when needed for matrix-vector multiplication. Matrices + can be 3-dimensional or higher by repeated nesting of + matrices. (In this way, a 2-dimensional matrix is really + thought of as a vector of vectors, and n-dimensional + ones as vectors of (n-1)-dimensional ones.) + + list (a,b,c) where a,b,c are arbitrary elements. + For example, (1+i, -3, <1,2,3>, Infinity). + The empty list () is allowed, and the parentheses are + optional if there is only one list. (This makes it + possible to make list-based answer checkers that + really know where the separations occur.) + + interval (a,b), (a,b], [a,b), [a,b], or [a,a] where a and b are + numbers or appropriate forms of infinity. + For example, (-INF,3], [4,4], [2,INF), (-INF,INF). + + union represented by 'U'. For example [-1,0) U (0,1]. + + string special predefined strings like NONE and DNE. + +These forms are what are used in the strings passed to Formula(). +If you want to create versions of these in perl, there are several +ways to do it. One way is to use the Compute() command, which takes a +string parses it and then evaluates the result (it is equivalent to +Formula(...)->eval). If the formula produces a vector, the result +will be a Vector constant that you can use in perl formulas by hand. + +For example: + + $v = Compute("<1,1,0> >< <-1,4,-2>"); + +would compute the dot product of the two vectors and assign the +resulting vector object to $v. + +Another way to generate constants of the various types is to use the +following routines. If their inputs are constant, they produce a +constant of the appropriate type. If an input is a formula, they +produce corresponding formula objects. + + Real(a) create a real number with "fuzzy" + comparisons (so that 1.0000001 == Real(1) is true). + + Complex(a,b) create a complex number a + b i + + Infinity creates the +infinity object + -(Infinity) creates -infinity + + Point(x1,...xn) or Point([x1,...,xn]) produces (x1,...,xn) + + Vector(x1,...,xn) or Vector([x1,...,xn]) produces <x1,...,xn> + + Matrix([a11,...,a1m],...,[am1,...,amn]) or + Matrix([[a11,...,a1m],...,[am1,...,amn]]) produces an n x m matrix + + List(a,...,b) produces a list with the given elements + + Interval('(',a,b,']') produces (a,b], (the other endpoints work as + expected. Use 'INF' and '-INF' for infinities.) + + Union(I1,...,In) takes the union of the n intervals. (where I1 to In + are intervals.) + + String(word) Produces a string object for the given word (if it + is a known word). This is mostly to be able to + call the ->cmp and ->TeX methods. + +For example, + + $a = random(-5,5,1) + $V = Vector($a,1-$a,$a**2+1); + +produces a vector with some random coordinates. + +Objects of these types also have TeX, string and perl methods, so you can +use: + + Vector(1,2,3)->TeX + +to produce a TeX version of the vector, just as you can with formulas. + +There are several "constant" functions that generate common constant +values. These include pi, i, j, k and Infininty. you can use these +in perl expressions as though they were their actual values: + + $z = $a + $b * i; + $v = $a*i + $b*j + $c*k; + $I = Infinity; + +Note that because of a peculiarity of perl, you need to use -(pi) +or - pi (with a space) rather than -pi, and similary for the other +functions. Without this, you will get an error message about an +ambiguity being resolved. (This is not a problem if you process your +expressions through the parser itself, only if you are writing +expressions in perl directly. Note that since student answers are +processed by the parser, not perl directly, they can write -pi without +problems.) + +Another useful command is Compute(), which evaluates a formula and +returns its value. This is one way to create point or vector-valued +constants, but there is an easier way discussed below. + +=head2 Specifying the Context + +You may have noticed that "i" was used in two different ways in the +examples above. In the first example, it was treated as a complex +number and the second as a coordinate unit vector. To control which +interpretation is used, you specify a parser "context". + +The context controls what operations and functions are defined in the +parser, what variables and constants to allow, how to interpret +various paretheses, and so on. Changing the context can completely +change the way a formula is interpreted. + +There are several predefined contexts: Numeric, Complex, Vector, +Interval and Full. (You can also define your own contexts, but that +will be described elsewhere.) To select a context, use the Context() +function, e.g. + + Context("Numeric"); + +selects the numeric context, where i, j and k have no special meaning, +points and vectors can't be used, and the only predefined variable is +'x'. + +On the other hand, Context("Vector") makes i, j and k represent the +unit coordinate vectors, and defines variables 'x', 'y' and 'z'. + +Context("Interval") is like numeric context, but it also defines the +parentheses so that they will form intervals (rather than points or +lists). + +Once you have selected a context, you can modify it to suit the +particular needs of your problem. The command + + $context = Context(); + +gets you a reference to the current context object (you can also use +something like + + $context = Context("Numeric"); + +to set the context and get its reference at the same time). Once you +have this reference, you can call the Context methods to change values +in the context. These are discussed in more detail in the +documentation of the Context object [not yet written], but some of the +more common actions are described here. + +To add a variable, use, for example, + + $context->variables->add(y=>'Real'); + +To delete any existing variables and replace them with new ones, use + + $context->variables->are(t=>'Real'); + +To remove a variable, use + + $context->variables->remove('t'); + +To get the names of the defind variables, use + + @names = $context->variables->names; + + +Similarly, you can add a named constant via + + $context->constants->add(M=>1/log(10)); + +and can change, remove or list the constants via methods like those +used for variables above. The command + + $M = $constant->constants->get('M'); + +will return the value of the consant M. (See the +pg/lib/Value/Context/Data.pm file for more information on the methods +you can call for the various types of context data.) + +To add new predefined words (like 'NONE' and 'DNE'), use something +like + + $constant->strings->add(TRUE=>{},FALSE=>{}); + +Note that strings are case-sensitive, so you might want to add + + $constant->strings->add( + true => {alias=>'TRUE'}, + false => {alias=>'FALSE'}, + ); + +so that either "TRUE" or "true" will be interpreted as TRUE. + +There are a number of values stored in the context that control things +like the tolerance used when comparing numbers, and so on. You +control these via commands like: + + $context->flags->set(tolerance=>.00001); + +For example, + + $context->flags->set(ijk=>1); + +will cause the output of all vectors to be written in ijk format +rather than <...> format. + +Finally, you can add or modify the operators and functions that are +available in the parser via calls to $context->operators and +$context->functions. See the files in webwork2/docs/parser/extensions +for examples of how to do this. + --- /dev/null +++ doc/MathObjects/README.pod @@ -0,0 +1,197 @@ +=head1 NAME + +MathObjects - Object system for manipulating mathematics in PG. + +=head1 OVERVIEW + +This directory contains the documentation for a new +mathematical-expression parser written in perl. It was developed for +use with the WeBWorK on-line homework system, but it can be used in +any perl program. + +The goal was to process vector-valued expressions, but the parser was +designed to be extensible, so that you could add your own functions, +operators, and data types. It is still a work in progress, but should +provide a framework for building more sophisticated expression handling. + +Currenlty, the parser understands: + +=over + +=item * real and complex numbers, + +=item * points, vectors, and matrices (with real or complex entries) + +=item * arbitrary lists of elements + +=item * intervals and unions of intervals + +=item * predefined strings like 'infinity' + +=back + +Some other useful features are that you can write sin^2 x for (sin(x))^2 +and sin^-1 x for arcsin(x), and so on. + +Most of the documentation still needs to be written, but you can get some +ideas from the samples in the problems and extensions directories, and by +reading the files in this directory. + +=head1 INSTALLATION + +The parser should already be installed as part of the WeBWorK 2.1 +distribution, so you should not need to install it separately. If you +don't seem to have it installed, then it can be obtained from the +Union CVS repository at +http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/WeBWorKCVS + +The README file in that directory contains the installation instructions. + +=head1 SAMPLE FILES + +Sample problems are given in the problems and extensions directories. Move +these to the templates directory of a course where you want to test the +Parser, and move the contents of the macros directory to that course's +macros directory. + +Now try looking at these problems using the Library Browser. Edit the +source to see how they work, and to read the comments within the code +itself. + +=head1 EXAMPLE FILES + +The 'problems' directory contains several examples that show how to use +Parser within your problem files. + +=over + +=item problems/sample01.pg + +Uses the parser to make a string into a formula that you can +evaluate and print in TeX form + +=item problems/sample02.pg + +Shows how to create formulas using perl's usual mathematical +expressions rather than character strings. + +=item problems/sample03.pg + +Shows how to use the parser's differentiation abilities. + +=item problems/sample04.pg + +=item problems/sample05.pg + +Use the parser in conjunction with the graphics macros to generate +function graphs on the fly. These also show how to create a +perl function to evaluate an expression. + +=item problems/sample06.pg + +Shows some simple use of vectors in a problem. + +=item problems/sample07.pg + +Example if using the build-in Real object and its answer +checker + +=item problems/sample08.pg + +Uses complex numbers and the built-in checker + +=item problems/sample09.pg + +=item problems/sample10.pg + +Demonstrates points and vectors and their answer checkers + +=item problems/sample11.pg + +=item problems/sample12.pg + +Shows the answer checkers for intervals and unions. + +=item problems/sample13.pg + +=item problems/sample14.pg + +=item problems/sample15.pg + +Demonstrate various list checkers, including a check for the +word 'NONE', which is a predefined string. + +=item problems/sample16.pg + +=item problems/sample17.pg + +=item problems/sample18.pg + +These show the multi-variable function checker in use (for +functions of the form R->R, R^2->R and R->R^3). + +=item problems/sample19.pg + +Uses the function checker to implement a "constant" that can +be used in formulas. + +=item problems/sample20.pg + +Shows how to use the parser's substitution abilities. + +=item problems/sample21.pg + +Checks for a list of points. + +=item problems/sample22.pg + +Shows how to provide named constants that the student can +use in his answer. + +=back + +The 'examples' directory contains samples that show how to extend the +parser to include your own functions, operators, and so on. There are also +some samples of how to call the methods available for Formula objects +generated by the parser, and what some error messages look like. + +=over + +=item examples/1-function.pg + +Adds a single-variable function to the parsers list of functions. + +=item examples/2-function.pg + +Adds a two-variable function to the parser. + +=item examples/3-operator.pg + +Adds a binary operator to the parser. (Unary operators are similar.) + +=item examples/4-list.pg + +Adds a new "list type" object. In this case, it's really an +operation [n,r] that returns n choose r. + +=item examples/5-list.pg + +Add a new "equality" operator that you can use to handle answers +like "x+y=0". + +=item examples/6-precedence.pg + +Shows an experimental precedence setting that can be used to make +sin 2x return sin(2x) rather than (sin(2))x. + +=item examples/7-context.pg + +Shows how to switch contexts (in this case, to complex and to vector +contexts), and how this affects the parsing. + +=item examples/8-answer.pg + +Implements a simple vector-valued answer checker using the +parser's computation and comparison ability. + +=back --- /dev/null +++ doc/MathObjects/MathObjectsAnswerCheckers.pod @@ -0,0 +1,423 @@ +=head1 MathObjects-based Answer Checkers + +MathObjects is designed to be used in two ways. First, you can use +it within your perl code when writing problems as a means of making it +easier to handle formulas, and in particular, to genarate be able to +use a single object to produce numeric values, TeX output and answer +strings. This avoids having to type a function three different ways +(which makes maintaining a problem much harder). Since MathObjects +also included vector and complex arthimatic, it is easier to work with +these types of values as well. + +The second reason for MathObjects is to use it to process student +input. This is accomplished through special answer checkers that are +part of the Parser package (rather than the traditional WeBWorK answer +checkers). Checkers are available for all the types of values that +the parser can produce (numbers, complex numbers, infinities, points, +vectors, intervals, unions, formulas, lists of numbers, lists of +points, lists of intervals, lists of formulas returning numbers, lists +of formulas returning points, and so on). + +To use one of these checkers, simply call the ->cmp method of the +object that represents the correct answer. For example: + + $n = Real(sqrt(2)); + ANS($n->cmp); + +will produce an answer checker that matches the square root of two. +Similarly, + + ANS(Vector(1,2,3)->cmp); + +matches the vector <1,2,3> (or any computation that produces it, e.g., +i+2j+3k, or <4,4,4>-<3,2,1>), while + + ANS(Interval("(-inf,3]")->cmp); + +matches the given interval. Other examples include: + + ANS(Infinity->cmp); + ANS(String('NONE')->cmp); + ANS(Union("(-inf,$a) U ($a,inf)")->cmp); + +and so on. + +Formulas are handled in the same way: + + ANS(Formula("x+1")->cmp); + + $a = random(-5,5,1); $b = random(-5,5,1); $x = random(-5,5,1); + $f = Formula("x^2 + $a x + $b")->reduce; + ANS($f->cmp); + ANS($f->eval(x=>$x)->cmp); + + $x = Formula('x'); + ANS((1+$a*$x)->cmp); + + Context("Vector")->variables->are(t=>'Real'); + $v = Formula("<t,t^2,t^3>"); $t = random(-5,5,1); + ANS($v->cmp); + ANS($v->eval(t=>$t)->cmp); + +and so on. + +Lists of items can be checked as easily: + + ANS(List(1,-1,0)->cmp); + ANS(List(Point($a,$b),Point($a,-$b))->cmp); + ANS(List(Vector(1,0,0),Vector(0,1,1))->cmp); + ANS(Compute("(-inf,2),(4,5)")->cmp); # easy way to get list of intervals + ANS(Formula("x, x+1, x^2-1")->cmp); + ANS(Formula("<x,2x>,<x,-2x>,<0,x>")->cmp); + ANS(List('NONE')->cmp); + +and so on. The last example may seem strange, as you could have used +ANS(String('NONE')->cmp), but there is a reason for using this type +of construction. You might be asking for one or more numbers (or +points, or whatever) or the word 'NONE' of there are no numbers (or +points). If you used String('NONE')->cmp, the student would get an +error message about a type mismatch if he entered a list of numbers, +but with List('NONE')->cmp, he will get appropriate error messages for +the wrong entries in the list. + +It is often appropriate to use the list checker in this way even when +the correct answer is a single value, if the student might type a list +of answers. + +On the other hand, using the list checker has its disadvantages. For +example, if you use + + ANS(Interval("(-inf,3]")->cmp); + +and the student enters (-inf,3), she will get a message indicating +that the type of interval is incorrect, while that would not be the +case if + + ANS(List(Interval("(-inf,3]"))->cmp); + +were used. (This is because the student doesn't know how many +intervals there are, so saying that the type of interval is wrong +would inform her that there is only one.) + +The rule of thumb is: the individual checkers can give more detailed +information about what is wrong with the student's answer; the list +checker allows a wider range of answers to be given without giving +away how many answers there are. If the student knows there's only +one, use the individual checker; if there may or may not be more than +one, use the list checker. + +Note that you can form lists of formulas as well. The following all +produce the same answer checker: + + ANS(List(Formula("x+1"),Formula("x-1"))->cmp); + + ANS(Formula("x+1,x-1")->cmp); # easier + + $f = Formula("x+1"); $g = Formula("x-1"); + ANS(List($f,$g)->cmp); + + $x = Formula('x'); + ANS(List($x+1,$x-1)->cmp); + +See the files in webwork2/doc/parser/problems for more +examples of using the parser's answer checkers. + +=head2 Controlling the Details of the Answer Checkers + +The action of the answer checkers can be modified by passing flags to +the cmp() method. For example: + + ANS(Real(pi)->cmp(showTypeWarnings=>0)); + +will prevent the answer checker from reporting errors due to the +student entering in the wrong type of answer (say a vector rather than +a number). + +=head3 Flags common to all answer checkers + +There are a number of flags common to all the checkers: + +=over + +=item S<C<< showTypeWarnings=>1 or 0 >>> + +show/don't show messages about student +answers not being of the right type. +(default: 1) + +=item S<C<< showEqualErrors=>1 or 0 >>> + +show/don't show messages produced by +trying to compare the professor and +student values for equality, e.g., +conversion errors between types. +(default: 1) + +=item S<C<< ignoreStrings=>1 or 0 >>> + +show/don't show type mismatch errors +produced by strings (so that 'NONE' will +not cause a type mismatch in a checker +looking for a list of numbers, for example). +(default: 1) + +=back + +In addition to these, the individual types have their own flags: + +=head3 Flags for Real()->cmp + +=over + +=item S<C<< ignoreInfinity=>1 or 0 >>> + +Don't report type mismatches if the +student enters an infinity. +(default: 1) + +=back + +=head3 Flags for String()->cmp + +=over + +=item S<C<< typeMatch=>value >>> + +Specifies the type of object that +the student should be allowed to enter +(in addition the string). +(default: 'Value::Real') + +=back + +=head3 Flags for Point()->cmp + +=over + +=item S<C<< showDimensionHints=>1 or 0 >>> + +show/don't show messages about the +wrong number of coordinates. +(default: 1) + +=item S<C<< showCoordinateHints=>1 or 0 >>> + +show/don't show message about +which coordinates are right. +(default: 1) + +=back + +=head3 Flags for Vector()->cmp + +=over + +=item S<C<< showDimensionHints=>1 or 0 >>> + +show/don't show messages about the +wrong number of coordinates. +(default: 1) + +=item S<C<< showCoordinateHints=>1 or 0 >>> + +show/don't show message about +which coordinates are right. +(default: 1) + +=item S<C<< promotePoints=>1 or 0 >>> + +do/don't allow the student to +enter a point rather than a vector. +(default: 1) + +=item S<C<< parallel=>1 or 0 >>> + +Mark the answer as correct if it +is parallel to the professor's answer. +Note that a value of 1 forces +showCoordinateHints to be 0. +(default: 0) + +=item S<C<< sameDirection=>1 or 0 >>> + +During a parallel check, mark the +answer as correct only if it is in +the same (not the opposite) +direction as the professor's answer. +(default: 0) + +=back + +=head3 Flags for Matrix()->cmp + +=over + +=item S<C<< showDimensionHints=>1 or 0 >>> + +show/don't show messages about the +wrong number of coordinates. +(default: 1) + +=back + +The default for showEqualErrors is set to 0 for Matrices, since +these errors usually are dimension errors, and that is handled +separately (and after the equality check). + +=head3 Flags for Interval()->cmp + +=over + +=item S<C<< showEndpointHints=>1 or 0 >>> + +do/don't show messages about which +endpoints are correct. +(default: 1) + +=item S<C<< showEndTypeHints=>1 or 0 >>> + +do/don't show messages about +whether the open/closed status of +the enpoints are correct (only +shown when the endpoints themselves +are correct). +(default: 1) + +=back + +=head3 Flags for Union()->cmp and List()->cmp + +all the flags from the Real()->cmp, plus: + +=over + +=item S<C<< showHints=>1 or 0 >>> + +do/don't show messages about which +entries are incorrect. +(default: $showPartialCorrectAnswers) + +=item S<C<< showLengthHints=>1 or 0 >>> + +do/don't show messages about having the +correct number of entries (only shown +when all the student answers are +correct but there are more needed, or +all the correct answsers are among the +ones given, but some extras were given). +(default: $showPartialCorrectAnswers) + +=item S<C<< partialCredit=>1 or 0 >>> + +do/don't give partial credit for when +some answers are right, but not all. +(default: $showPartialCorrectAnswers) +(currently the default is 0 since WW +can't handle partial credit properly). + +=item S<C<< ordered=>1 or 0 >>> + +give credit only if the student answers +are in the same order as the +professor's answers. +(default: 0) + +=item S<C<< entry_type=>'a (name)' >>> + +The string to use in error messages +about type mismatches. +(default: dynamically determined from list) + +=item S<C<< list_type=>'a (name)' >>> + +The string to use in error messages +about numbers of entries in the list. +(default: dynamically determined from list) + +=item S<C<< typeMatch=>value >>> + +Specifies the type of object that +the student should be allowed to enter +in the list (determines what +constitutes a type mismatch error). +(default: dynamically determined from list) + +=item S<C<< requireParenMatch=>1 or 0 >>> + +Do/don't require the parentheses in the +student's answer to match those in the +professor's answer exactly. +(default: 1) + +=item S<C<< removeParens=>1 or 0 >>> + +Do/don't remove the parentheses from the +professor's list as part of the correct +answer string. This is so that if you +use List() to create the list (which +doesn't allow you to control the parens +directly), you can still get a list +with no parentheses. +(default: 0 for List() and 1 for Formula()) + +=back + +=head3 Flags for Formula()->cmp + +The flags for formulas are dependent on the type of the result of +the formula. If the result is a list or union, it gets the flags +for that type above, otherwise it gets that flags of the Real +type above. + +More flags need to be added in order to allow more control over the +answer checkers to give the full flexibility of the traditional +WeBWorK answer checkers. Note that some things, like whether trig +functions are allowed in the answer, are controlled through the +Context() rather than the answer checker itself. For example, + + Context()->functions->undefine('sin','cos','tan'); + +would remove those three functions from use. (One would need to remove +cot, sec, csc, arcsin, asin, etc., to do this properly; there could be +a function call to do this.) + +Similarly, which arithmetic operations are available is controlled +through Context()->operations. + +The tolerances used in comparing numbers are part of the Context as +well. You can set these via: + + Context()->flags->set( + tolerance => .0001, # the relative or absolute tolerance + tolType => 'relative', # or 'absolute' + zeroLevel => 1E-14, # when to use zeroLevelTol + zeroLevelTol => 1E-12, # smaller than this matches zero + # when one of the two is less + # than zeroLevel + limits => [-2,2], # limits for variables in formulas + num_points => 5, # the number of test points + ); + +[These need to be handled better.] + +Note that for testing formulas, you can override the limits and +num_points settings by setting these fields of the formula itself: + + $f = Formula("sqrt(x-10)"); + $f->{limits} = [10,12]; + + $f = Formula("log(xy)"); + $f->{limits} = [[.1,2],[.1,2]]; # x and y limits + +You can also specify the test points explicitly: + + $f = Formula("sqrt(x-10)"); + $f->{test_points} = [[11],[11.5],[12]]; + + $f = Formula("log(xy)"); + $f->{test_points} = [[.1,.1],[.1,.5],[.1,.75], + [.5,.1],[.5,.5],[.5,.75]]; + +[There still needs to be a means of handling the tolerances similarly, +and through the ->cmp() call itself.] + |
From: Sam H. v. a. <we...@ma...> - 2007-09-28 00:28:50
|
Update of /webwork/cvs/system/pg/doc/MathObjects In directory devel.webwork.rochester.edu:/tmp/cvs-serv70036/MathObjects Log Message: Directory /webwork/cvs/system/pg/doc/MathObjects added to the repository |
From: Sam H. v. a. <we...@ma...> - 2007-09-28 00:24:31
|
Log Message: ----------- removed mathobjects for now... re-adding shortly Removed Files: ------------- pg/doc/MathObjects: README.pod Revision Data ------------- --- doc/MathObjects/README.pod +++ /dev/null @@ -1,197 +0,0 @@ -=head1 NAME - -MathObjects - Object system for manipulating mathematics in PG. - -=head1 OVERVIEW - -This directory contains the documentation for a new -mathematical-expression parser written in perl. It was developed for -use with the WeBWorK on-line homework system, but it can be used in -any perl program. - -The goal was to process vector-valued expressions, but the parser was -designed to be extensible, so that you could add your own functions, -operators, and data types. It is still a work in progress, but should -provide a framework for building more sophisticated expression handling. - -Currenlty, the parser understands: - -=over - -=item * real and complex numbers, - -=item * points, vectors, and matrices (with real or complex entries) - -=item * arbitrary lists of elements - -=item * intervals and unions of intervals - -=item * predefined strings like 'infinity' - -=back - -Some other useful features are that you can write sin^2 x for (sin(x))^2 -and sin^-1 x for arcsin(x), and so on. - -Most of the documentation still needs to be written, but you can get some -ideas from the samples in the problems and extensions directories, and by -reading the files in the docs directory. - -=head1 INSTALLATION - -The parser should already be installed as part of the WeBWorK 2.1 -distribution, so you should not need to install it separately. If you -don't seem to have it installed, then it can be obtained from the -Union CVS repository at -http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/WeBWorKCVS - -The README file in that directory contains the installation instructions. - -=head1 SAMPLE FILES - -Sample problems are given in the problems and extensions directories. Move -these to the templates directory of a course where you want to test the -Parser, and move the contents of the macros directory to that course's -macros directory. - -Now try looking at these problems using the Library Browser. Edit the -source to see how they work, and to read the comments within the code -itself. - -=head1 EXAMPLE FILES - -The 'problems' directory contains several examples that show how to use -Parser within your problem files. - -=over - -=item problems/sample01.pg - -Uses the parser to make a string into a formula that you can -evaluate and print in TeX form - -=item problems/sample02.pg - -Shows how to create formulas using perl's usual mathematical -expressions rather than character strings. - -=item problems/sample03.pg - -Shows how to use the parser's differentiation abilities. - -=item problems/sample04.pg - -=item problems/sample05.pg - -Use the parser in conjunction with the graphics macros to generate -function graphs on the fly. These also show how to create a -perl function to evaluate an expression. - -=item problems/sample06.pg - -Shows some simple use of vectors in a problem. - -=item problems/sample07.pg - -Example if using the build-in Real object and its answer -checker - -=item problems/sample08.pg - -Uses complex numbers and the built-in checker - -=item problems/sample09.pg - -=item problems/sample10.pg - -Demonstrates points and vectors and their answer checkers - -=item problems/sample11.pg - -=item problems/sample12.pg - -Shows the answer checkers for intervals and unions. - -=item problems/sample13.pg - -=item problems/sample14.pg - -=item problems/sample15.pg - -Demonstrate various list checkers, including a check for the -word 'NONE', which is a predefined string. - -=item problems/sample16.pg - -=item problems/sample17.pg - -=item problems/sample18.pg - -These show the multi-variable function checker in use (for -functions of the form R->R, R^2->R and R->R^3). - -=item problems/sample19.pg - -Uses the function checker to implement a "constant" that can -be used in formulas. - -=item problems/sample20.pg - -Shows how to use the parser's substitution abilities. - -=item problems/sample21.pg - -Checks for a list of points. - -=item problems/sample22.pg - -Shows how to provide named constants that the student can -use in his answer. - -=back - -The 'examples' directory contains samples that show how to extend the -parser to include your own functions, operators, and so on. There are also -some samples of how to call the methods available for Formula objects -generated by the parser, and what some error messages look like. - -=over - -=item examples/1-function.pg - -Adds a single-variable function to the parsers list of functions. - -=item examples/2-function.pg - -Adds a two-variable function to the parser. - -=item examples/3-operator.pg - -Adds a binary operator to the parser. (Unary operators are similar.) - -=item examples/4-list.pg - -Adds a new "list type" object. In this case, it's really an -operation [n,r] that returns n choose r. - -=item examples/5-list.pg - -Add a new "equality" operator that you can use to handle answers -like "x+y=0". - -=item examples/6-precedence.pg - -Shows an experimental precedence setting that can be used to make -sin 2x return sin(2x) rather than (sin(2))x. - -=item examples/7-context.pg - -Shows how to switch contexts (in this case, to complex and to vector -contexts), and how this affects the parsing. - -=item examples/8-answer.pg - -Implements a simple vector-valued answer checker using the -parser's computation and comparison ability. - -=back |
From: Sam H. v. a. <we...@ma...> - 2007-09-28 00:23:23
|
Log Message: ----------- removed spurrious "see also" Modified Files: -------------- pg/doc/MathObjects: README.pod Revision Data ------------- Index: README.pod =================================================================== RCS file: /webwork/cvs/system/pg/doc/MathObjects/README.pod,v retrieving revision 1.1 retrieving revision 1.2 diff -Ldoc/MathObjects/README.pod -Ldoc/MathObjects/README.pod -u -r1.1 -r1.2 --- doc/MathObjects/README.pod +++ doc/MathObjects/README.pod @@ -42,7 +42,8 @@ The parser should already be installed as part of the WeBWorK 2.1 distribution, so you should not need to install it separately. If you don't seem to have it installed, then it can be obtained from the -Union CVS repository at http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/WeBWorKCVS +Union CVS repository at +http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/WeBWorKCVS The README file in that directory contains the installation instructions. @@ -194,8 +195,3 @@ parser's computation and comparison ability. =back - -=head1 SEE ALSO - -L<problems/sample01.pg>. - |
From: Sam H. v. a. <we...@ma...> - 2007-09-28 00:22:51
|
Log Message: ----------- converted to pod Added Files: ----------- webwork2/doc/parser/docs: ParserAnswerCheckers.pod UsingParser.pod Removed Files: ------------- webwork2/doc/parser/docs: ParserAnswerCheckers.txt UsingParser.txt Revision Data ------------- --- /dev/null +++ doc/parser/docs/UsingParser.pod @@ -0,0 +1,393 @@ +=head1 USING MATHOBJECTS + +To use MathObjects in your own problems, you need to load the +"MathObjects.pl" macro file: + + loadMacros("Parser.pl"); + +which defines the commands you need to interact with MathObjects. +Once you have done that, you can call the MathObjects functions to create +formulas for you. The main call is Formula(), which takes a string and +returns a parsed version of the string. For example: + + $f = Formula("x^2 + 3x + 1"); + +will set $f to a reference to the parsed version of the formula. + +=head2 Working With Formulas + +A formula has a number of methods that you can call. These include: + +=over + +=item $f->eval(x=>5) + +Evaluate the formula when x is 5. +If $f has more variables than that, then +you must provide additional values, as in +$f->eval(x=>3,y=>1/2); + +=item $f->reduce + +Tries to remove redundent items from your +formula. For example, Formula("1x+0") returns "x". +Reduce tries to factor out negatives and do +some other adjustments as well. (There still +needs to be more work done on this. What it does +is correct, but not always smart, and there need +to be many more situations covered.) All the +reduction rules can be individually enabled +or disabled using the Context()->reduction->set() +method, but the documentation for the various +rules is not yet ready. + +=item $f->substitute(x=>5) + +Replace x by the value 5 throughout (you may want +to reduce the result afterword, as this is not +done automatically). Note that you can replace a +variable by another formula, if you wish. To make +this easier, substitute will apply Formula() to +any string values automatically. E.g., + Formula("x-1")->substitute(x=>"y") +returns "y-1" as a formula. + +=item $f->string + +returns a string representation of the formula +(should be equivalent to the original, though not +necessarily equal to it). + +=item $f->TeX + +returns a LaTeX representation of the formula. +You can use this in BEGIN_TEXT...END_TEXT blocks +as follows: + + BEGIN_TEXT + Suppose \(f(x) = \{$f->TeX}\). ... + END_TEXT + +=item $f->perl + +returns a representation of the formula that could +be evaluated by perl's eval() function. + +=item $f->perlFunction + +returns a perl code block that can be called to +evaluate the function. For example: + + $f = Formula('x^2 + 3')->perlFunction; + $y = &$f(5); + +will assign the value 28 to $y. +You can also pass a function name to perlFunction +to get a named function to call: + + Formula('x^2 + 3')->perlFunction('f'); + $y = f(5); + +If the formula involves more than one variable, +then the paramaters should be given in +alphabetical order. + + Formula('x^2 + y')->perlFunction('f'); + $z = f(5,3); # $z is 28. + +Alternatively, you can tell the order for the +parameters: + + Formula('x^2 + y')->perlFunction('f',['y','x']); + $z = f(5,3); $ now $z is 14. + +=back + +=head2 Combining Formulas + +There is a second way to create formulas. Once you have a formula, you can +create additional formulas simply by using perls' built-in operations and +functions, which have been overloaded to handle formulas. For example, + + $x = Formula('x'); + $f = 3*x**2 + 2*$x - 1; + +makes $f be a formula, and is equivalent to having done + + $f = Formula("3x^2 + 2x - 1"); + +This can be very convenient, but also has some pitfalls. First, you +need to include '*' for multiplication, since perl doesn't do implied +multiplication, and you must remember to use '**' not '^'. (If you use '^' +on a formula, the parser will remind you to use '**'.) Second, the +precedences of the operators in perl are fixed, and so changes you make to +the precedence table for the parser are not reflected in formulas produced +in this way. (The reason '^' is not overloaded to do exponentiation is +that the precedence of '^' is wrong for that in perl, and can't be +changed.) As long as you leave the default precedences, however, things +should work as you expect. + +Note that the standard functions, like sin, cos, etc, are overloaded to +generate appropriate formulas when their values are formulas. For example, + + $x = Formula('x'); + $f = cos(3*$x + 1); + +produces the same result as $f = Formula("cos(3x+1)"); and you can then go +on to output its TeX form, etc. + +=head2 Special Syntax + +This parser has support for some things that are missing from the current +one, like absolute values. You can say |1+x| rather than abs(1+x) +(though both are allowed), and even |1 - |x|| works. + +Also, you can use sin^2(x) (or even sin^2 x) to get (sin(x))^2. + +Finally, you can use sin^-1(x) to get arcsin(x). + +There is an experimental set of operator precedences that make it possible +to write sin 2x + 3 and get sin(2x) + 3. See examples/7-precedence.pg +for some details. + +=head2 The Formula Types + +The parser understands a wide range of data types, including real and +complex numbers, points, vectors, matrices, arbitrary lists, intervals, +unions of intervals, and predefined words. Each has a syntax for use +within formulas, as described below: + + numbers the usual form: 153, 233.5, -2.456E-3, etc. + + complex a + b i where a and b are numbers: 1+i, -5i, 6-7i, etc. + + infinitites the words 'infinity' or '-infinity' (or several + equivalents). + + point (a,b,c) where a, b and c are real or complex numbers. + any number of coordinates are allowed. Eg, (1,2), + (1,0,0,0), (-1,2,-3). Points are promoted to vectors + automatically, when necessary. + + vector <a,b,c> or a i + b j + c k (when used in vector context). + As with points, vectors can have any number of + coordinates. For example, <1,0,0>, <-1,3>, <x,1-x>, etc. + + matrix [[a11,...,a1n],...[am1,...amn]], i.e., use [..] around + each row, and around the matrix itself. The elements + are separated by commas (not spaces). e.g, + [[1,2],[3,4]] (a 2x2 matrix) + [1,2] (a 1x2 matrix, really a vector) + [[1],[2]] (a 2x1 matrix, ie. column vector) + Points and vectors are promoted to matrices when + appropriate. Vectors are converted to column vectors + when needed for matrix-vector multiplication. Matrices + can be 3-dimensional or higher by repeated nesting of + matrices. (In this way, a 2-dimensional matrix is really + thought of as a vector of vectors, and n-dimensional + ones as vectors of (n-1)-dimensional ones.) + + list (a,b,c) where a,b,c are arbitrary elements. + For example, (1+i, -3, <1,2,3>, Infinity). + The empty list () is allowed, and the parentheses are + optional if there is only one list. (This makes it + possible to make list-based answer checkers that + really know where the separations occur.) + + interval (a,b), (a,b], [a,b), [a,b], or [a,a] where a and b are + numbers or appropriate forms of infinity. + For example, (-INF,3], [4,4], [2,INF), (-INF,INF). + + union represented by 'U'. For example [-1,0) U (0,1]. + + string special predefined strings like NONE and DNE. + +These forms are what are used in the strings passed to Formula(). +If you want to create versions of these in perl, there are several +ways to do it. One way is to use the Compute() command, which takes a +string parses it and then evaluates the result (it is equivalent to +Formula(...)->eval). If the formula produces a vector, the result +will be a Vector constant that you can use in perl formulas by hand. + +For example: + + $v = Compute("<1,1,0> >< <-1,4,-2>"); + +would compute the dot product of the two vectors and assign the +resulting vector object to $v. + +Another way to generate constants of the various types is to use the +following routines. If their inputs are constant, they produce a +constant of the appropriate type. If an input is a formula, they +produce corresponding formula objects. + + Real(a) create a real number with "fuzzy" + comparisons (so that 1.0000001 == Real(1) is true). + + Complex(a,b) create a complex number a + b i + + Infinity creates the +infinity object + -(Infinity) creates -infinity + + Point(x1,...xn) or Point([x1,...,xn]) produces (x1,...,xn) + + Vector(x1,...,xn) or Vector([x1,...,xn]) produces <x1,...,xn> + + Matrix([a11,...,a1m],...,[am1,...,amn]) or + Matrix([[a11,...,a1m],...,[am1,...,amn]]) produces an n x m matrix + + List(a,...,b) produces a list with the given elements + + Interval('(',a,b,']') produces (a,b], (the other endpoints work as + expected. Use 'INF' and '-INF' for infinities.) + + Union(I1,...,In) takes the union of the n intervals. (where I1 to In + are intervals.) + + String(word) Produces a string object for the given word (if it + is a known word). This is mostly to be able to + call the ->cmp and ->TeX methods. + +For example, + + $a = random(-5,5,1) + $V = Vector($a,1-$a,$a**2+1); + +produces a vector with some random coordinates. + +Objects of these types also have TeX, string and perl methods, so you can +use: + + Vector(1,2,3)->TeX + +to produce a TeX version of the vector, just as you can with formulas. + +There are several "constant" functions that generate common constant +values. These include pi, i, j, k and Infininty. you can use these +in perl expressions as though they were their actual values: + + $z = $a + $b * i; + $v = $a*i + $b*j + $c*k; + $I = Infinity; + +Note that because of a peculiarity of perl, you need to use -(pi) +or - pi (with a space) rather than -pi, and similary for the other +functions. Without this, you will get an error message about an +ambiguity being resolved. (This is not a problem if you process your +expressions through the parser itself, only if you are writing +expressions in perl directly. Note that since student answers are +processed by the parser, not perl directly, they can write -pi without +problems.) + +Another useful command is Compute(), which evaluates a formula and +returns its value. This is one way to create point or vector-valued +constants, but there is an easier way discussed below. + +=head2 Specifying the Context + +You may have noticed that "i" was used in two different ways in the +examples above. In the first example, it was treated as a complex +number and the second as a coordinate unit vector. To control which +interpretation is used, you specify a parser "context". + +The context controls what operations and functions are defined in the +parser, what variables and constants to allow, how to interpret +various paretheses, and so on. Changing the context can completely +change the way a formula is interpreted. + +There are several predefined contexts: Numeric, Complex, Vector, +Interval and Full. (You can also define your own contexts, but that +will be described elsewhere.) To select a context, use the Context() +function, e.g. + + Context("Numeric"); + +selects the numeric context, where i, j and k have no special meaning, +points and vectors can't be used, and the only predefined variable is +'x'. + +On the other hand, Context("Vector") makes i, j and k represent the +unit coordinate vectors, and defines variables 'x', 'y' and 'z'. + +Context("Interval") is like numeric context, but it also defines the +parentheses so that they will form intervals (rather than points or +lists). + +Once you have selected a context, you can modify it to suit the +particular needs of your problem. The command + + $context = Context(); + +gets you a reference to the current context object (you can also use +something like + + $context = Context("Numeric"); + +to set the context and get its reference at the same time). Once you +have this reference, you can call the Context methods to change values +in the context. These are discussed in more detail in the +documentation of the Context object [not yet written], but some of the +more common actions are described here. + +To add a variable, use, for example, + + $context->variables->add(y=>'Real'); + +To delete any existing variables and replace them with new ones, use + + $context->variables->are(t=>'Real'); + +To remove a variable, use + + $context->variables->remove('t'); + +To get the names of the defind variables, use + + @names = $context->variables->names; + + +Similarly, you can add a named constant via + + $context->constants->add(M=>1/log(10)); + +and can change, remove or list the constants via methods like those +used for variables above. The command + + $M = $constant->constants->get('M'); + +will return the value of the consant M. (See the +pg/lib/Value/Context/Data.pm file for more information on the methods +you can call for the various types of context data.) + +To add new predefined words (like 'NONE' and 'DNE'), use something +like + + $constant->strings->add(TRUE=>{},FALSE=>{}); + +Note that strings are case-sensitive, so you might want to add + + $constant->strings->add( + true => {alias=>'TRUE'}, + false => {alias=>'FALSE'}, + ); + +so that either "TRUE" or "true" will be interpreted as TRUE. + +There are a number of values stored in the context that control things +like the tolerance used when comparing numbers, and so on. You +control these via commands like: + + $context->flags->set(tolerance=>.00001); + +For example, + + $context->flags->set(ijk=>1); + +will cause the output of all vectors to be written in ijk format +rather than <...> format. + +Finally, you can add or modify the operators and functions that are +available in the parser via calls to $context->operators and +$context->functions. See the files in webwork2/docs/parser/extensions +for examples of how to do this. + --- doc/parser/docs/UsingParser.txt +++ /dev/null @@ -1,383 +0,0 @@ -USING THE PARSER: - -To use the new parser in your own problems, you need to load the -"Parser.pl" macro file: - - loadMacros("Parser.pl"); - -which defines the commands you need to interact with the parser. -Once you have done that, you can call the Parser functions to create -formulas for you. The main call is Formula(), which takes a string and -returns a parsed version of the string. For example: - - $f = Formula("x^2 + 3x + 1"); - -will set $f to a reference to the parsed version of the formula. - - -WORKING WITH FORMULAS: - -A formula has a number of methods that you can call. These include: - - $f->eval(x=>5) Evaluate the formula when x is 5. - If $f has more variables than that, then - you must provide additional values, as in - $f->eval(x=>3,y=>1/2); - - $f->reduce Tries to remove redundent items from your - formula. For example, Formula("1x+0") returns "x". - Reduce tries to factor out negatives and do - some other adjustments as well. (There still - needs to be more work done on this. What it does - is correct, but not always smart, and there need - to be many more situations covered.) All the - reduction rules can be individually enabled - or disabled using the Context()->reduction->set() - method, but the documentation for the various - rules is not yet ready. - - $f->substitute(x=>5) Replace x by the value 5 throughout (you may want - to reduce the result afterword, as this is not - done automatically). Note that you can replace a - variable by another formula, if you wish. To make - this easier, substitute will apply Formula() to - any string values automatically. E.g., - Formula("x-1")->substitute(x=>"y") - returns "y-1" as a formula. - - $f->string returns a string representation of the formula - (should be equivalent to the original, though not - necessarily equal to it). - - $f->TeX returns a LaTeX representation of the formula. - You can use this in BEGIN_TEXT...END_TEXT blocks - as follows: - - BEGIN_TEXT - Suppose \(f(x) = \{$f->TeX}\). ... - END_TEXT - - $f->perl returns a representation of the formula that could - be evaluated by perl's eval() function. - - $f->perlFunction returns a perl code block that can be called to - evaluate the function. For example: - - $f = Formula('x^2 + 3')->perlFunction; - $y = &$f(5); - - will assign the value 28 to $y. - You can also pass a function name to perlFunction - to get a named function to call: - - Formula('x^2 + 3')->perlFunction('f'); - $y = f(5); - - If the formula involves more than one variable, - then the paramaters should be given in - alphabetical order. - - Formula('x^2 + y')->perlFunction('f'); - $z = f(5,3); # $z is 28. - - Alternatively, you can tell the order for the - parameters: - - Formula('x^2 + y')->perlFunction('f',['y','x']); - $z = f(5,3); $ now $z is 14. - - -COMBINING FORMULAS: - -There is a second way to create formulas. Once you have a formula, you can -create additional formulas simply by using perls' built-in operations and -functions, which have been overloaded to handle formulas. For example, - - $x = Formula('x'); - $f = 3*x**2 + 2*$x - 1; - -makes $f be a formula, and is equivalent to having done - - $f = Formula("3x^2 + 2x - 1"); - -This can be very convenient, but also has some pitfalls. First, you -need to include '*' for multiplication, since perl doesn't do implied -multiplication, and you must remember to use '**' not '^'. (If you use '^' -on a formula, the parser will remind you to use '**'.) Second, the -precedences of the operators in perl are fixed, and so changes you make to -the precedence table for the parser are not reflected in formulas produced -in this way. (The reason '^' is not overloaded to do exponentiation is -that the precedence of '^' is wrong for that in perl, and can't be -changed.) As long as you leave the default precedences, however, things -should work as you expect. - -Note that the standard functions, like sin, cos, etc, are overloaded to -generate appropriate formulas when their values are formulas. For example, - - $x = Formula('x'); - $f = cos(3*$x + 1); - -produces the same result as $f = Formula("cos(3x+1)"); and you can then go -on to output its TeX form, etc. - - -SPECIAL SYNTAX: - -This parser has support for some things that are missing from the current -one, like absolute values. You can say |1+x| rather than abs(1+x) -(though both are allowed), and even |1 - |x|| works. - -Also, you can use sin^2(x) (or even sin^2 x) to get (sin(x))^2. - -Finally, you can use sin^-1(x) to get arcsin(x). - -There is an experimental set of operator precedences that make it possible -to write sin 2x + 3 and get sin(2x) + 3. See examples/7-precedence.pg -for some details. - - -THE FORMULA TYPES: - -The parser understands a wide range of data types, including real and -complex numbers, points, vectors, matrices, arbitrary lists, intervals, -unions of intervals, and predefined words. Each has a syntax for use -within formulas, as described below: - - numbers the usual form: 153, 233.5, -2.456E-3, etc. - - complex a + b i where a and b are numbers: 1+i, -5i, 6-7i, etc. - - infinitites the words 'infinity' or '-infinity' (or several - equivalents). - - point (a,b,c) where a, b and c are real or complex numbers. - any number of coordinates are allowed. Eg, (1,2), - (1,0,0,0), (-1,2,-3). Points are promoted to vectors - automatically, when necessary. - - vector <a,b,c> or a i + b j + c k (when used in vector context). - As with points, vectors can have any number of - coordinates. For example, <1,0,0>, <-1,3>, <x,1-x>, etc. - - matrix [[a11,...,a1n],...[am1,...amn]], i.e., use [..] around - each row, and around the matrix itself. The elements - are separated by commas (not spaces). e.g, - [[1,2],[3,4]] (a 2x2 matrix) - [1,2] (a 1x2 matrix, really a vector) - [[1],[2]] (a 2x1 matrix, ie. column vector) - Points and vectors are promoted to matrices when - appropriate. Vectors are converted to column vectors - when needed for matrix-vector multiplication. Matrices - can be 3-dimensional or higher by repeated nesting of - matrices. (In this way, a 2-dimensional matrix is really - thought of as a vector of vectors, and n-dimensional - ones as vectors of (n-1)-dimensional ones.) - - list (a,b,c) where a,b,c are arbitrary elements. - For example, (1+i, -3, <1,2,3>, Infinity). - The empty list () is allowed, and the parentheses are - optional if there is only one list. (This makes it - possible to make list-based answer checkers that - really know where the separations occur.) - - interval (a,b), (a,b], [a,b), [a,b], or [a,a] where a and b are - numbers or appropriate forms of infinity. - For example, (-INF,3], [4,4], [2,INF), (-INF,INF). - - union represented by 'U'. For example [-1,0) U (0,1]. - - string special predefined strings like NONE and DNE. - -These forms are what are used in the strings passed to Formula(). -If you want to create versions of these in perl, there are several -ways to do it. One way is to use the Compute() command, which takes a -string parses it and then evaluates the result (it is equivalent to -Formula(...)->eval). If the formula produces a vector, the result -will be a Vector constant that you can use in perl formulas by hand. - -For example: - - $v = Compute("<1,1,0> >< <-1,4,-2>"); - -would compute the dot product of the two vectors and assign the -resulting vector object to $v. - -Another way to generate constants of the various types is to use the -following routines. If their inputs are constant, they produce a -constant of the appropriate type. If an input is a formula, they -produce corresponding formula objects. - - Real(a) create a real number with "fuzzy" - comparisons (so that 1.0000001 == Real(1) is true). - - Complex(a,b) create a complex number a + b i - - Infinity creates the +infinity object - -(Infinity) creates -infinity - - Point(x1,...xn) or Point([x1,...,xn]) produces (x1,...,xn) - - Vector(x1,...,xn) or Vector([x1,...,xn]) produces <x1,...,xn> - - Matrix([a11,...,a1m],...,[am1,...,amn]) or - Matrix([[a11,...,a1m],...,[am1,...,amn]]) produces an n x m matrix - - List(a,...,b) produces a list with the given elements - - Interval('(',a,b,']') produces (a,b], (the other endpoints work as - expected. Use 'INF' and '-INF' for infinities.) - - Union(I1,...,In) takes the union of the n intervals. (where I1 to In - are intervals.) - - String(word) Produces a string object for the given word (if it - is a known word). This is mostly to be able to - call the ->cmp and ->TeX methods. - -For example, - - $a = random(-5,5,1) - $V = Vector($a,1-$a,$a**2+1); - -produces a vector with some random coordinates. - -Objects of these types also have TeX, string and perl methods, so you can -use: - - Vector(1,2,3)->TeX - -to produce a TeX version of the vector, just as you can with formulas. - -There are several "constant" functions that generate common constant -values. These include pi, i, j, k and Infininty. you can use these -in perl expressions as though they were their actual values: - - $z = $a + $b * i; - $v = $a*i + $b*j + $c*k; - $I = Infinity; - -Note that because of a peculiarity of perl, you need to use -(pi) -or - pi (with a space) rather than -pi, and similary for the other -functions. Without this, you will get an error message about an -ambiguity being resolved. (This is not a problem if you process your -expressions through the parser itself, only if you are writing -expressions in perl directly. Note that since student answers are -processed by the parser, not perl directly, they can write -pi without -problems.) - -Another useful command is Compute(), which evaluates a formula and -returns its value. This is one way to create point or vector-valued -constants, but there is an easier way discussed below. - - -SPECIFYING THE CONTEXT - -You may have noticed that "i" was used in two different ways in the -examples above. In the first example, it was treated as a complex -number and the second as a coordinate unit vector. To control which -interpretation is used, you specify a parser "context". - -The context controls what operations and functions are defined in the -parser, what variables and constants to allow, how to interpret -various paretheses, and so on. Changing the context can completely -change the way a formula is interpreted. - -There are several predefined contexts: Numeric, Complex, Vector, -Interval and Full. (You can also define your own contexts, but that -will be described elsewhere.) To select a context, use the Context() -function, e.g. - - Context("Numeric"); - -selects the numeric context, where i, j and k have no special meaning, -points and vectors can't be used, and the only predefined variable is -'x'. - -On the other hand, Context("Vector") makes i, j and k represent the -unit coordinate vectors, and defines variables 'x', 'y' and 'z'. - -Context("Interval") is like numeric context, but it also defines the -parentheses so that they will form intervals (rather than points or -lists). - -Once you have selected a context, you can modify it to suit the -particular needs of your problem. The command - - $context = Context(); - -gets you a reference to the current context object (you can also use -something like - - $context = Context("Numeric"); - -to set the context and get its reference at the same time). Once you -have this reference, you can call the Context methods to change values -in the context. These are discussed in more detail in the -documentation of the Context object [not yet written], but some of the -more common actions are described here. - -To add a variable, use, for example, - - $context->variables->add(y=>'Real'); - -To delete any existing variables and replace them with new ones, use - - $context->variables->are(t=>'Real'); - -To remove a variable, use - - $context->variables->remove('t'); - -To get the names of the defind variables, use - - @names = $context->variables->names; - - -Similarly, you can add a named constant via - - $context->constants->add(M=>1/log(10)); - -and can change, remove or list the constants via methods like those -used for variables above. The command - - $M = $constant->constants->get('M'); - -will return the value of the consant M. (See the -pg/lib/Value/Context/Data.pm file for more information on the methods -you can call for the various types of context data.) - -To add new predefined words (like 'NONE' and 'DNE'), use something -like - - $constant->strings->add(TRUE=>{},FALSE=>{}); - -Note that strings are case-sensitive, so you might want to add - - $constant->strings->add( - true => {alias=>'TRUE'}, - false => {alias=>'FALSE'}, - ); - -so that either "TRUE" or "true" will be interpreted as TRUE. - -There are a number of values stored in the context that control things -like the tolerance used when comparing numbers, and so on. You -control these via commands like: - - $context->flags->set(tolerance=>.00001); - -For example, - - $context->flags->set(ijk=>1); - -will cause the output of all vectors to be written in ijk format -rather than <...> format. - -Finally, you can add or modify the operators and functions that are -available in the parser via calls to $context->operators and -$context->functions. See the files in webwork2/docs/parser/extensions -for examples of how to do this. - - - - --- /dev/null +++ doc/parser/docs/ParserAnswerCheckers.pod @@ -0,0 +1,423 @@ +=head1 MathObjects-based Answer Checkers + +MathObjects is designed to be used in two ways. First, you can use +it within your perl code when writing problems as a means of making it +easier to handle formulas, and in particular, to genarate be able to +use a single object to produce numeric values, TeX output and answer +strings. This avoids having to type a function three different ways +(which makes maintaining a problem much harder). Since MathObjects +also included vector and complex arthimatic, it is easier to work with +these types of values as well. + +The second reason for MathObjects is to use it to process student +input. This is accomplished through special answer checkers that are +part of the Parser package (rather than the traditional WeBWorK answer +checkers). Checkers are available for all the types of values that +the parser can produce (numbers, complex numbers, infinities, points, +vectors, intervals, unions, formulas, lists of numbers, lists of +points, lists of intervals, lists of formulas returning numbers, lists +of formulas returning points, and so on). + +To use one of these checkers, simply call the ->cmp method of the +object that represents the correct answer. For example: + + $n = Real(sqrt(2)); + ANS($n->cmp); + +will produce an answer checker that matches the square root of two. +Similarly, + + ANS(Vector(1,2,3)->cmp); + +matches the vector <1,2,3> (or any computation that produces it, e.g., +i+2j+3k, or <4,4,4>-<3,2,1>), while + + ANS(Interval("(-inf,3]")->cmp); + +matches the given interval. Other examples include: + + ANS(Infinity->cmp); + ANS(String('NONE')->cmp); + ANS(Union("(-inf,$a) U ($a,inf)")->cmp); + +and so on. + +Formulas are handled in the same way: + + ANS(Formula("x+1")->cmp); + + $a = random(-5,5,1); $b = random(-5,5,1); $x = random(-5,5,1); + $f = Formula("x^2 + $a x + $b")->reduce; + ANS($f->cmp); + ANS($f->eval(x=>$x)->cmp); + + $x = Formula('x'); + ANS((1+$a*$x)->cmp); + + Context("Vector")->variables->are(t=>'Real'); + $v = Formula("<t,t^2,t^3>"); $t = random(-5,5,1); + ANS($v->cmp); + ANS($v->eval(t=>$t)->cmp); + +and so on. + +Lists of items can be checked as easily: + + ANS(List(1,-1,0)->cmp); + ANS(List(Point($a,$b),Point($a,-$b))->cmp); + ANS(List(Vector(1,0,0),Vector(0,1,1))->cmp); + ANS(Compute("(-inf,2),(4,5)")->cmp); # easy way to get list of intervals + ANS(Formula("x, x+1, x^2-1")->cmp); + ANS(Formula("<x,2x>,<x,-2x>,<0,x>")->cmp); + ANS(List('NONE')->cmp); + +and so on. The last example may seem strange, as you could have used +ANS(String('NONE')->cmp), but there is a reason for using this type +of construction. You might be asking for one or more numbers (or +points, or whatever) or the word 'NONE' of there are no numbers (or +points). If you used String('NONE')->cmp, the student would get an +error message about a type mismatch if he entered a list of numbers, +but with List('NONE')->cmp, he will get appropriate error messages for +the wrong entries in the list. + +It is often appropriate to use the list checker in this way even when +the correct answer is a single value, if the student might type a list +of answers. + +On the other hand, using the list checker has its disadvantages. For +example, if you use + + ANS(Interval("(-inf,3]")->cmp); + +and the student enters (-inf,3), she will get a message indicating +that the type of interval is incorrect, while that would not be the +case if + + ANS(List(Interval("(-inf,3]"))->cmp); + +were used. (This is because the student doesn't know how many +intervals there are, so saying that the type of interval is wrong +would inform her that there is only one.) + +The rule of thumb is: the individual checkers can give more detailed +information about what is wrong with the student's answer; the list +checker allows a wider range of answers to be given without giving +away how many answers there are. If the student knows there's only +one, use the individual checker; if there may or may not be more than +one, use the list checker. + +Note that you can form lists of formulas as well. The following all +produce the same answer checker: + + ANS(List(Formula("x+1"),Formula("x-1"))->cmp); + + ANS(Formula("x+1,x-1")->cmp); # easier + + $f = Formula("x+1"); $g = Formula("x-1"); + ANS(List($f,$g)->cmp); + + $x = Formula('x'); + ANS(List($x+1,$x-1)->cmp); + +See the files in webwork2/doc/parser/problems for more +examples of using the parser's answer checkers. + +=head2 Controlling the Details of the Answer Checkers + +The action of the answer checkers can be modified by passing flags to +the cmp() method. For example: + + ANS(Real(pi)->cmp(showTypeWarnings=>0)); + +will prevent the answer checker from reporting errors due to the +student entering in the wrong type of answer (say a vector rather than +a number). + +=head3 Flags common to all answer checkers + +There are a number of flags common to all the checkers: + +=over + +=item S<C<< showTypeWarnings=>1 or 0 >>> + +show/don't show messages about student +answers not being of the right type. +(default: 1) + +=item S<C<< showEqualErrors=>1 or 0 >>> + +show/don't show messages produced by +trying to compare the professor and +student values for equality, e.g., +conversion errors between types. +(default: 1) + +=item S<C<< ignoreStrings=>1 or 0 >>> + +show/don't show type mismatch errors +produced by strings (so that 'NONE' will +not cause a type mismatch in a checker +looking for a list of numbers, for example). +(default: 1) + +=back + +In addition to these, the individual types have their own flags: + +=head3 Flags for Real()->cmp + +=over + +=item S<C<< ignoreInfinity=>1 or 0 >>> + +Don't report type mismatches if the +student enters an infinity. +(default: 1) + +=back + +=head3 Flags for String()->cmp + +=over + +=item S<C<< typeMatch=>value >>> + +Specifies the type of object that +the student should be allowed to enter +(in addition the string). +(default: 'Value::Real') + +=back + +=head3 Flags for Point()->cmp + +=over + +=item S<C<< showDimensionHints=>1 or 0 >>> + +show/don't show messages about the +wrong number of coordinates. +(default: 1) + +=item S<C<< showCoordinateHints=>1 or 0 >>> + +show/don't show message about +which coordinates are right. +(default: 1) + +=back + +=head3 Flags for Vector()->cmp + +=over + +=item S<C<< showDimensionHints=>1 or 0 >>> + +show/don't show messages about the +wrong number of coordinates. +(default: 1) + +=item S<C<< showCoordinateHints=>1 or 0 >>> + +show/don't show message about +which coordinates are right. +(default: 1) + +=item S<C<< promotePoints=>1 or 0 >>> + +do/don't allow the student to +enter a point rather than a vector. +(default: 1) + +=item S<C<< parallel=>1 or 0 >>> + +Mark the answer as correct if it +is parallel to the professor's answer. +Note that a value of 1 forces +showCoordinateHints to be 0. +(default: 0) + +=item S<C<< sameDirection=>1 or 0 >>> + +During a parallel check, mark the +answer as correct only if it is in +the same (not the opposite) +direction as the professor's answer. +(default: 0) + +=back + +=head3 Flags for Matrix()->cmp + +=over + +=item S<C<< showDimensionHints=>1 or 0 >>> + +show/don't show messages about the +wrong number of coordinates. +(default: 1) + +=back + +The default for showEqualErrors is set to 0 for Matrices, since +these errors usually are dimension errors, and that is handled +separately (and after the equality check). + +=head3 Flags for Interval()->cmp + +=over + +=item S<C<< showEndpointHints=>1 or 0 >>> + +do/don't show messages about which +endpoints are correct. +(default: 1) + +=item S<C<< showEndTypeHints=>1 or 0 >>> + +do/don't show messages about +whether the open/closed status of +the enpoints are correct (only +shown when the endpoints themselves +are correct). +(default: 1) + +=back + +=head3 Flags for Union()->cmp and List()->cmp + +all the flags from the Real()->cmp, plus: + +=over + +=item S<C<< showHints=>1 or 0 >>> + +do/don't show messages about which +entries are incorrect. +(default: $showPartialCorrectAnswers) + +=item S<C<< showLengthHints=>1 or 0 >>> + +do/don't show messages about having the +correct number of entries (only shown +when all the student answers are +correct but there are more needed, or +all the correct answsers are among the +ones given, but some extras were given). +(default: $showPartialCorrectAnswers) + +=item S<C<< partialCredit=>1 or 0 >>> + +do/don't give partial credit for when +some answers are right, but not all. +(default: $showPartialCorrectAnswers) +(currently the default is 0 since WW +can't handle partial credit properly). + +=item S<C<< ordered=>1 or 0 >>> + +give credit only if the student answers +are in the same order as the +professor's answers. +(default: 0) + +=item S<C<< entry_type=>'a (name)' >>> + +The string to use in error messages +about type mismatches. +(default: dynamically determined from list) + +=item S<C<< list_type=>'a (name)' >>> + +The string to use in error messages +about numbers of entries in the list. +(default: dynamically determined from list) + +=item S<C<< typeMatch=>value >>> + +Specifies the type of object that +the student should be allowed to enter +in the list (determines what +constitutes a type mismatch error). +(default: dynamically determined from list) + +=item S<C<< requireParenMatch=>1 or 0 >>> + +Do/don't require the parentheses in the +student's answer to match those in the +professor's answer exactly. +(default: 1) + +=item S<C<< removeParens=>1 or 0 >>> + +Do/don't remove the parentheses from the +professor's list as part of the correct +answer string. This is so that if you +use List() to create the list (which +doesn't allow you to control the parens +directly), you can still get a list +with no parentheses. +(default: 0 for List() and 1 for Formula()) + +=back + +=head3 Flags for Formula()->cmp + +The flags for formulas are dependent on the type of the result of +the formula. If the result is a list or union, it gets the flags +for that type above, otherwise it gets that flags of the Real +type above. + +More flags need to be added in order to allow more control over the +answer checkers to give the full flexibility of the traditional +WeBWorK answer checkers. Note that some things, like whether trig +functions are allowed in the answer, are controlled through the +Context() rather than the answer checker itself. For example, + + Context()->functions->undefine('sin','cos','tan'); + +would remove those three functions from use. (One would need to remove +cot, sec, csc, arcsin, asin, etc., to do this properly; there could be +a function call to do this.) + +Similarly, which arithmetic operations are available is controlled +through Context()->operations. + +The tolerances used in comparing numbers are part of the Context as +well. You can set these via: + + Context()->flags->set( + tolerance => .0001, # the relative or absolute tolerance + tolType => 'relative', # or 'absolute' + zeroLevel => 1E-14, # when to use zeroLevelTol + zeroLevelTol => 1E-12, # smaller than this matches zero + # when one of the two is less + # than zeroLevel + limits => [-2,2], # limits for variables in formulas + num_points => 5, # the number of test points + ); + +[These need to be handled better.] + +Note that for testing formulas, you can override the limits and +num_points settings by setting these fields of the formula itself: + + $f = Formula("sqrt(x-10)"); + $f->{limits} = [10,12]; + + $f = Formula("log(xy)"); + $f->{limits} = [[.1,2],[.1,2]]; # x and y limits + +You can also specify the test points explicitly: + + $f = Formula("sqrt(x-10)"); + $f->{test_points} = [[11],[11.5],[12]]; + + $f = Formula("log(xy)"); + $f->{test_points} = [[.1,.1],[.1,.5],[.1,.75], + [.5,.1],[.5,.5],[.5,.75]]; + +[There still needs to be a means of handling the tolerances similarly, +and through the ->cmp() call itself.] + --- doc/parser/docs/ParserAnswerCheckers.txt +++ /dev/null @@ -1,348 +0,0 @@ -PARSER-BASED ANSWER CHECKERS - -The new parser is designed to be used in two ways. First, you can use -it within your perl code when writing problems as a means of making it -easier to handle formulas, and in particular, to genarate be able to -use a single object to produce numeric values, TeX output and answer -strings. This avoids having to type a function three different ways -(which makes maintaining a problem much harder). Since the parser -also included vector and complex arthimatic, it is easier to work with -these types of values as well. - -The second reason for the parser is to use it to process student -input. This is accomplished through special answer checkers that are -part of the Parser package (rather than the traditional WeBWorK answer -checkers). Checkers are available for all the types of values that -the parser can produce (numbers, complex numbers, infinities, points, -vectors, intervals, unions, formulas, lists of numbers, lists of -points, lists of intervals, lists of formulas returning numbers, lists -of formulas returning points, and so on). - -To use one of these checkers, simply call the ->cmp method of the -object that represents the correct answer. For example: - - $n = Real(sqrt(2)); - ANS($n->cmp); - -will produce an answer checker that matches the square root of two. -Similarly, - - ANS(Vector(1,2,3)->cmp); - -matches the vector <1,2,3> (or any computation that produces it, e.g., -i+2j+3k, or <4,4,4>-<3,2,1>), while - - ANS(Interval("(-inf,3]")->cmp); - -matches the given interval. Other examples include: - - ANS(Infinity->cmp); - ANS(String('NONE')->cmp); - ANS(Union("(-inf,$a) U ($a,inf)")->cmp); - -and so on. - -Formulas are handled in the same way: - - ANS(Formula("x+1")->cmp); - - $a = random(-5,5,1); $b = random(-5,5,1); $x = random(-5,5,1); - $f = Formula("x^2 + $a x + $b")->reduce; - ANS($f->cmp); - ANS($f->eval(x=>$x)->cmp); - - $x = Formula('x'); - ANS((1+$a*$x)->cmp); - - Context("Vector")->variables->are(t=>'Real'); - $v = Formula("<t,t^2,t^3>"); $t = random(-5,5,1); - ANS($v->cmp); - ANS($v->eval(t=>$t)->cmp); - -and so on. - -Lists of items can be checked as easily: - - ANS(List(1,-1,0)->cmp); - ANS(List(Point($a,$b),Point($a,-$b))->cmp); - ANS(List(Vector(1,0,0),Vector(0,1,1))->cmp); - ANS(Compute("(-inf,2),(4,5)")->cmp); # easy way to get list of intervals - ANS(Formula("x, x+1, x^2-1")->cmp); - ANS(Formula("<x,2x>,<x,-2x>,<0,x>")->cmp); - ANS(List('NONE')->cmp); - -and so on. The last example may seem strange, as you could have used -ANS(String('NONE')->cmp), but there is a reason for using this type -of construction. You might be asking for one or more numbers (or -points, or whatever) or the word 'NONE' of there are no numbers (or -points). If you used String('NONE')->cmp, the student would get an -error message about a type mismatch if he entered a list of numbers, -but with List('NONE')->cmp, he will get appropriate error messages for -the wrong entries in the list. - -It is often appropriate to use the list checker in this way even when -the correct answer is a single value, if the student might type a list -of answers. - -On the other hand, using the list checker has its disadvantages. For -example, if you use - - ANS(Interval("(-inf,3]")->cmp); - -and the student enters (-inf,3), she will get a message indicating -that the type of interval is incorrect, while that would not be the -case if - - ANS(List(Interval("(-inf,3]"))->cmp); - -were used. (This is because the student doesn't know how many -intervals there are, so saying that the type of interval is wrong -would inform her that there is only one.) - -The rule of thumb is: the individual checkers can give more detailed -information about what is wrong with the student's answer; the list -checker allows a wider range of answers to be given without giving -away how many answers there are. If the student knows there's only -one, use the individual checker; if there may or may not be more than -one, use the list checker. - -Note that you can form lists of formulas as well. The following all -produce the same answer checker: - - ANS(List(Formula("x+1"),Formula("x-1"))->cmp); - - ANS(Formula("x+1,x-1")->cmp); # easier - - $f = Formula("x+1"); $g = Formula("x-1"); - ANS(List($f,$g)->cmp); - - $x = Formula('x'); - ANS(List($x+1,$x-1)->cmp); - -See the files in webwork2/doc/parser/problems for more -examples of using the parser's answer checkers. - - -CONTROLLING THE DETAILS OF THE ANSWER CHECKERS: - -The action of the answer checkers can be modified by passing flags to -the cmp() method. For example: - - ANS(Real(pi)->cmp(showTypeWarnings=>0)); - -will prevent the answer checker from reporting errors due to the -student entering in the wrong type of answer (say a vector rather than -a number). - -There are a number of flags common to all the checkers: - - showTypeWarnings=>1 or 0 show/don't show messages about student - answers not being of the right type. - (default: 1) - - showEqualErrors=>1 or 0 show/don't show messages produced by - trying to compare the professor and - student values for equality, e.g., - conversion errors between types. - (default: 1) - - ignoreStrings=>1 or 0 show/don't show type mismatch errors - produced by strings (so that 'NONE' will - not cause a type mismatch in a checker - looking for a list of numbers, for example). - (default: 1) - -In addition to these, the individual types have their own flags: - - Real()->cmp: - - ignoreInfinity=>1 or 0 Don't report type mismatches if the - student enters an infinity. - (default: 1) - - String()->cmp: - - typeMatch=>value Specifies the type of object that - the student should be allowed to enter - (in addition the string). - (default: 'Value::Real') - - - Point()->cmp: - - showDimensionHints=>1 or 0 show/don't show messages about the - wrong number of coordinates. - (default: 1) - - showCoordinateHints=>1 or 0 show/don't show message about - which coordinates are right. - (default: 1) - - - Vector()->cmp: - - showDimensionHints=>1 or 0 show/don't show messages about the - wrong number of coordinates. - (default: 1) - - showCoordinateHints=>1 or 0 show/don't show message about - which coordinates are right. - (default: 1) - - promotePoints=>1 or 0 do/don't allow the student to - enter a point rather than a vector. - (default: 1) - - parallel=>1 or 0 Mark the answer as correct if it - is parallel to the professor's answer. - Note that a value of 1 forces - showCoordinateHints to be 0. - (default: 0) - - sameDirection=>1 or 0 During a parallel check, mark the - answer as correct only if it is in - the same (not the opposite) - direction as the professor's answer. - (default: 0) - - Matrix()->cmp: - - showDimensionHints=>1 or 0 show/don't show messages about the - wrong number of coordinates. - (default: 1) - - The default for showEqualErrors is set to 0 for Matrices, since - these errors usually are dimension errors, and that is handled - separately (and after the equality check). - - - Interval()->cmp: - - showEndpointHints=>1 or 0 do/don't show messages about which - endpoints are correct. - (default: 1) - - showEndTypeHints=>1 or 0 do/don't show messages about - whether the open/closed status of - the enpoints are correct (only - shown when the endpoints themselves - are correct). - (default: 1) - - - Union()->cmp and - List()->cmp: - - all the flags from the Real()->cmp, plus: - - showHints=>1 or 0 do/don't show messages about which - entries are incorrect. - (default: $showPartialCorrectAnswers) - - showLengthHints=>1 or 0 do/don't show messages about having the - correct number of entries (only shown - when all the student answers are - correct but there are more needed, or - all the correct answsers are among the - ones given, but some extras were given). - (default: $showPartialCorrectAnswers) - - partialCredit=>1 or 0 do/don't give partial credit for when - some answers are right, but not all. - (default: $showPartialCorrectAnswers) - (currently the default is 0 since WW - can't handle partial credit properly). - - ordered=>1 or 0 give credit only if the student answers - are in the same order as the - professor's answers. - (default: 0) - - entry_type=>'a (name)' The string to use in error messages - about type mismatches. - (default: dynamically determined from list) - - list_type=>'a (name)' The string to use in error messages - about numbers of entries in the list. - (default: dynamically determined from list) - - typeMatch=>value Specifies the type of object that - the student should be allowed to enter - in the list (determines what - constitutes a type mismatch error). - (default: dynamically determined from list) - - requireParenMatch=>1 or 0 - Do/don't require the parentheses in the - student's answer to match those in the - professor's answer exactly. - (default: 1) - - removeParens=>1 or 0 Do/don't remove the parentheses from the - professor's list as part of the correct - answer string. This is so that if you - use List() to create the list (which - doesn't allow you to control the parens - directly), you can still get a list - with no parentheses. - (default: 0 for List() and 1 for Formula()) - - Formula()->cmp: - - The flags for formulas are dependent on the type of the result of - the formula. If the result is a list or union, it gets the flags - for that type above, otherwise it gets that flags of the Real - type above. - - -More flags need to be added in order to allow more control over the -answer checkers to give the full flexibility of the traditional -WeBWorK answer checkers. Note that some things, like whether trig -functions are allowed in the answer, are controlled through the -Context() rather than the answer checker itself. For example, - - Context()->functions->undefine('sin','cos','tan'); - -would remove those three functions from use. (One would need to remove -cot, sec, csc, arcsin, asin, etc., to do this properly; there could be -a function call to do this.) - -Similarly, which arithmetic operations are available is controlled -through Context()->operations. - -The tolerances used in comparing numbers are part of the Context as -well. You can set these via: - - Context()->flags->set( - tolerance => .0001, # the relative or absolute tolerance - tolType => 'relative', # or 'absolute' - zeroLevel => 1E-14, # when to use zeroLevelTol - zeroLevelTol => 1E-12, # smaller than this matches zero - # when one of the two is less - # than zeroLevel - limits => [-2,2], # limits for variables in formulas - num_points => 5, # the number of test points - ); - -[These need to be handled better.] - -Note that for testing formulas, you can override the limits and -num_points settings by setting these fields of the formula itself: - - $f = Formula("sqrt(x-10)"); - $f->{limits} = [10,12]; - - $f = Formula("log(xy)"); - $f->{limits} = [[.1,2],[.1,2]]; # x and y limits - -You can also specify the test points explicitly: - - $f = Formula("sqrt(x-10)"); - $f->{test_points} = [[11],[11.5],[12]]; - - $f = Formula("log(xy)"); - $f->{test_points} = [[.1,.1],[.1,.5],[.1,.75], - [.5,.1],[.5,.5],[.5,.75]]; - -[There still needs to be a means of handling the tolerances similarly, -and through the ->cmp() call itself.] |
From: Sam H. v. a. <we...@ma...> - 2007-09-26 20:02:44
|
Log Message: ----------- test pod Added Files: ----------- pg/doc/MathObjects: README.pod Revision Data ------------- --- /dev/null +++ doc/MathObjects/README.pod @@ -0,0 +1,201 @@ +=head1 NAME + +MathObjects - Object system for manipulating mathematics in PG. + +=head1 OVERVIEW + +This directory contains the documentation for a new +mathematical-expression parser written in perl. It was developed for +use with the WeBWorK on-line homework system, but it can be used in +any perl program. + +The goal was to process vector-valued expressions, but the parser was +designed to be extensible, so that you could add your own functions, +operators, and data types. It is still a work in progress, but should +provide a framework for building more sophisticated expression handling. + +Currenlty, the parser understands: + +=over + +=item * real and complex numbers, + +=item * points, vectors, and matrices (with real or complex entries) + +=item * arbitrary lists of elements + +=item * intervals and unions of intervals + +=item * predefined strings like 'infinity' + +=back + +Some other useful features are that you can write sin^2 x for (sin(x))^2 +and sin^-1 x for arcsin(x), and so on. + +Most of the documentation still needs to be written, but you can get some +ideas from the samples in the problems and extensions directories, and by +reading the files in the docs directory. + +=head1 INSTALLATION + +The parser should already be installed as part of the WeBWorK 2.1 +distribution, so you should not need to install it separately. If you +don't seem to have it installed, then it can be obtained from the +Union CVS repository at http://devel.webwork.rochester.edu/twiki/bin/view/Webwork/WeBWorKCVS + +The README file in that directory contains the installation instructions. + +=head1 SAMPLE FILES + +Sample problems are given in the problems and extensions directories. Move +these to the templates directory of a course where you want to test the +Parser, and move the contents of the macros directory to that course's +macros directory. + +Now try looking at these problems using the Library Browser. Edit the +source to see how they work, and to read the comments within the code +itself. + +=head1 EXAMPLE FILES + +The 'problems' directory contains several examples that show how to use +Parser within your problem files. + +=over + +=item problems/sample01.pg + +Uses the parser to make a string into a formula that you can +evaluate and print in TeX form + +=item problems/sample02.pg + +Shows how to create formulas using perl's usual mathematical +expressions rather than character strings. + +=item problems/sample03.pg + +Shows how to use the parser's differentiation abilities. + +=item problems/sample04.pg + +=item problems/sample05.pg + +Use the parser in conjunction with the graphics macros to generate +function graphs on the fly. These also show how to create a +perl function to evaluate an expression. + +=item problems/sample06.pg + +Shows some simple use of vectors in a problem. + +=item problems/sample07.pg + +Example if using the build-in Real object and its answer +checker + +=item problems/sample08.pg + +Uses complex numbers and the built-in checker + +=item problems/sample09.pg + +=item problems/sample10.pg + +Demonstrates points and vectors and their answer checkers + +=item problems/sample11.pg + +=item problems/sample12.pg + +Shows the answer checkers for intervals and unions. + +=item problems/sample13.pg + +=item problems/sample14.pg + +=item problems/sample15.pg + +Demonstrate various list checkers, including a check for the +word 'NONE', which is a predefined string. + +=item problems/sample16.pg + +=item problems/sample17.pg + +=item problems/sample18.pg + +These show the multi-variable function checker in use (for +functions of the form R->R, R^2->R and R->R^3). + +=item problems/sample19.pg + +Uses the function checker to implement a "constant" that can +be used in formulas. + +=item problems/sample20.pg + +Shows how to use the parser's substitution abilities. + +=item problems/sample21.pg + +Checks for a list of points. + +=item problems/sample22.pg + +Shows how to provide named constants that the student can +use in his answer. + +=back + +The 'examples' directory contains samples that show how to extend the +parser to include your own functions, operators, and so on. There are also +some samples of how to call the methods available for Formula objects +generated by the parser, and what some error messages look like. + +=over + +=item examples/1-function.pg + +Adds a single-variable function to the parsers list of functions. + +=item examples/2-function.pg + +Adds a two-variable function to the parser. + +=item examples/3-operator.pg + +Adds a binary operator to the parser. (Unary operators are similar.) + +=item examples/4-list.pg + +Adds a new "list type" object. In this case, it's really an +operation [n,r] that returns n choose r. + +=item examples/5-list.pg + +Add a new "equality" operator that you can use to handle answers +like "x+y=0". + +=item examples/6-precedence.pg + +Shows an experimental precedence setting that can be used to make +sin 2x return sin(2x) rather than (sin(2))x. + +=item examples/7-context.pg + +Shows how to switch contexts (in this case, to complex and to vector +contexts), and how this affects the parsing. + +=item examples/8-answer.pg + +Implements a simple vector-valued answer checker using the +parser's computation and comparison ability. + +=back + +=head1 SEE ALSO + +L<problems/sample01.pg>. + |
From: Sam H. v. a. <we...@ma...> - 2007-09-26 18:00:06
|
Update of /webwork/cvs/system/pg/doc/MathObjects In directory devel.webwork.rochester.edu:/tmp/cvs-serv88918/MathObjects Log Message: Directory /webwork/cvs/system/pg/doc/MathObjects added to the repository |
From: Sam H. v. a. <we...@ma...> - 2007-09-26 17:59:53
|
Update of /webwork/cvs/system/pg/doc In directory devel.webwork.rochester.edu:/tmp/cvs-serv88905/doc Log Message: Directory /webwork/cvs/system/pg/doc added to the repository |
From: Sam H. v. a. <we...@ma...> - 2007-09-26 17:26:03
|
Log Message: ----------- never got anywhere with this, unfortunately Removed Files: ------------- webwork2/doc/docbook/install: Installing-WeBWorK.xml Revision Data ------------- --- doc/docbook/install/Installing-WeBWorK.xml +++ /dev/null @@ -1,155 +0,0 @@ -<?xml version="1.0" standalone="no"?> -<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" -"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ -<!ENTITY WW "WeBWorK"> -]> -<article> - <articleinfo> - <title>Installing WeBWorK</title> - <author><firstname>Sam</firstname><surname>Hathaway</surname></author> - <copyright><year>2005</year><holder>The WeBWorK Project</holder></copyright> - </articleinfo> - <section id="intro"> - <title>Introduction</title> - <para>FiXME: purpose of this article, assumptions, etc.</para> - </section> - <section id="sysreq"> - <title>System Requirements</title> - <para>&WW; requires several software packages to run. The installation procedure varies depending on your operating system.</para> - <section id="os"> - <title>Operating System</title> - <para>&WW; runs on most POSIX-compliant operating systems. It has been tested on FreeBSD, Linux, Solaris, Mac OS X.</para> - </section> - <section id="perl"> - <title>Perl</title> - <para>&WW; requires Perl 5.6 or higher and several of the core modules included in the Perl distribution.</para> - <itemizedlist> - <listitem><simpara><ulink type="http" url="http://perl.org/">Perl web site</ulink></simpara></listitem> - <listitem><simpara><ulink type="http" url="http://packages.debian.org/perl">Debian package perl</ulink></simpara></listitem> - </itemizedlist> - <para>The following non-core Perl modules are also required. All are available from <ulink type="http" url="http://cpan.org/">CPAN</ulink>, and many OS vendors provide packages of these modules. To see if <replaceable>Module</replaceable> is installed on your system, run <command>perl -M<replaceable>Module</replaceable> -e 'print "installed!\n"'</command>. To install <replaceable>Module</replaceable> from CPAN, run <command>perl -MCPAN -e "install <replaceable>Module</replaceable>"</command>.</para> - <segmentedlist> - <title>Required Perl Modules</title> - <?dbhtml list-presentation="table"?> - <segtitle>Module</segtitle> - <segtitle>Debian package</segtitle> - <seglistitem> - <seg>Apache::Request</seg> - <seg><ulink type="http" url="http://packages.debian.org/libapache-request-perl">libapache-request-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>Data::UUID</seg> - <seg>not available<footnote><para>The package <ulink type="http" url="http://packages.debian.org/libossp-uuid-perl">libossp-uuid-perl</ulink> provides a clone of Data::UUID that alledgedly has the same interface. It has not been tested with &WW;</para></footnote></seg> - </seglistitem> - <seglistitem> - <seg>String::ShellQuote</seg> - <seg><ulink type="http" url="http://packages.debian.org/libstring-shellquote-perl">libstring-shellquote-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>DateTime</seg> - <seg><ulink type="http" url="http://packages.debian.org/libdatetime-perl">libdatetime-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>Date::Format</seg> - <seg><ulink type="http" url="http://packages.debian.org/libtimedate-perl">libtimedate-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>Date::Parse</seg> - <seg><ulink type="http" url="http://packages.debian.org/libtimedate-perl">libtimedate-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>GD</seg> - <seg><ulink type="http" url="http://packages.debian.org/libgd-gd2-perl">libgd-gd2-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>Mail::Sender</seg> - <seg><ulink type="http" url="http://packages.debian.org/libmail-sender-perl">libmail-sender-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>SOAP::Lite</seg> - <seg><ulink type="http" url="http://packages.debian.org/libsoap-lite-perl">libsoap-lite-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>Time::HiRes</seg> - <seg><ulink type="http" url="http://packages.debian.org/libtime-hires-perl">libtime-hires-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>XML::Parser</seg> - <seg><ulink type="http" url="http://packages.debian.org/libxml-parser-perl">libxml-parser-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>XML::Parser::EasyTree</seg> - <seg>not available</seg> - </seglistitem> - <seglistitem> - <seg>XML::Writer</seg> - <seg><ulink type="http" url="http://packages.debian.org/libxml-writer-perl">libxml-writer-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>DBI</seg> - <seg><ulink type="http" url="http://packages.debian.org/libdbi-perl">libdbi-perl</ulink></seg> - </seglistitem> - <seglistitem> - <seg>DBD::mysql</seg> - <seg><ulink type="http" url="http://packages.debian.org/libdbd-mysql-perl">libdbd-mysql-perl</ulink></seg> - </seglistitem> - </segmentedlist> - </section> - <section id="apache"> - <title>Apache 1.3</title> - <para>&WW; requires Apache 1.3.x and the <literal>mod_alias</literal> module.</para> - <itemizedlist> - <listitem><simpara><ulink type="http" url="http://httpd.apache.org/">Apache web site</ulink></simpara></listitem> - <listitem><simpara><ulink type="http" url="http://packages.debian.org/apache">Debian package apache</ulink></simpara></listitem> - </itemizedlist> - </section> - <section id="modperl"> - <title>mod_perl</title> - <para>&WW; is a mod_perl application and requires mod_perl 1.x. If compiling mod_perl from source, use the <envar>EVERYTHING=1</envar> flag to enable all mod_perl features. Most vendors compile their mod_perl packages with this setting enabled.</para> - <itemizedlist> - <listitem><simpara><ulink type="http" url="http://perl.apache.org/">mod_perl web site</ulink></simpara></listitem> - <listitem><simpara><ulink type="http" url="http://packages.debian.org/libapache-mod-perl">Debian package libapache-mod-perl</ulink></simpara></listitem> - </itemizedlist> - </section> - <section id="mysql"> - <title>MySQL</title> - <para>&WW; stores its data in a MySQL database. &WW; has been tested with MySQL 3 and 4. It should work with MySQL 5 as well. The MySQL server can be on the same machine as &WW; or on a remote machine. You will need the <command>mysql</command> client to create the &WW; database.</para> - <itemizedlist> - <listitem><simpara><ulink type="http" url="http://mysql.com/">MySQL web site</ulink></simpara></listitem> - <listitem><simpara><ulink type="http" url="http://packages.debian.org/mysql-server">Debian package mysql-server</ulink></simpara></listitem> - </itemizedlist> - </section> - <section id="latex"> - <title>LaTeX</title> - <para>&WW; uses LaTeX for generating hardcopy output and displaying mathematics graphically. Any standard LaTeX distribution that provides the commands <command>latex</command> and <command>pdflatex</command> should work. &WW; has been tested with teTeX.</para> - <itemizedlist> - <listitem><simpara><ulink type="http" url="http://tug.org/tetex/">teTeX web site</ulink></simpara></listitem> - <listitem><simpara>Debian packages <ulink type="http" url="http://packages.debian.org/tetex-bin">tetex-bin</ulink> and <ulink type="http" url="http://packages.debian.org/tetex-extra">tetex-extra</ulink></simpara></listitem> - </itemizedlist> - </section> - <section id="netpbm"> - <title>Netpbm</title> - <para>&WW; requires Netpbm, an image manipulation library, to convert images among the GIF, PNG, and EPS formats.</para> - <itemizedlist> - <listitem><simpara><ulink type="http" url="http://netpbm.sf.net/">Netpbm web site</ulink></simpara></listitem> - <listitem><simpara>Debian package <ulink type="http" url="http://packages.debian.org/netpbm">netpbm</ulink></simpara></listitem> - </itemizedlist> - </section> - <section id="dvipng"> - <title>dvipng</title> - <para>&WW; uses dvipng to display mathematics graphically. It is only required if you wish to use the <literal>images</literal> display mode. &WW; is initially configured to work with dvipng 1.0 or greater, but can be reconfigured to work with dvipng 0.8 or 0.9. dvipng requires the <filename>preview.sty</filename> file from the preview-latex package.</para> - <itemizedlist> - <listitem><simpara><ulink type="http" url="http://dvipng.sf.net/">dvipng web site</ulink></simpara></listitem> - <listitem><simpara>Debian packages <ulink type="http" url="http://packages.debian.org/dvipng">dvipng</ulink> and <ulink type="http" url="http://packages.debian.org/preview-latex-style">preview-latex-style</ulink></simpara></listitem> - </itemizedlist> - </section> - <section id="tth"> - <title>tth</title> - <para>&WW; uses TtH to display mathematics as formatted HTML. It is only required if you wish to use the <literal>formatted-text</literal> display mode.</para> - <itemizedlist> - <listitem><simpara><ulink type="http" url="http://hutchinson.belmont.ma.us/tth/">TtH web site</ulink></simpara></listitem> - <listitem><simpara>Debian package <ulink type="http" url="http://packages.debian.org/tth">tth</ulink></simpara></listitem> - </itemizedlist> - </section> - </section> -</article> \ No newline at end of file |
From: Matt L. v. a. <we...@ma...> - 2007-09-26 16:17:14
|
Log Message: ----------- Added GD perl module as a prerequisite Modified Files: -------------- ww_question_server/bin/setup: setup.pl Revision Data ------------- Index: setup.pl =================================================================== RCS file: /webwork/cvs/system/ww_question_server/bin/setup/setup.pl,v retrieving revision 1.8 retrieving revision 1.9 diff -Lbin/setup/setup.pl -Lbin/setup/setup.pl -u -r1.8 -r1.9 --- bin/setup/setup.pl +++ bin/setup/setup.pl @@ -149,7 +149,7 @@ #CPAN Module Administration $preqCheck = promptUser("Check CPAN Prerequisites(y,n)",'y'); if($preqCheck eq 'y') { - @modulesNeeded = ($modperlCPAN,$apacheSoapCPAN,'LWP::Simple','Pod::WSDL','Safe','MIME::Base64','File::Which'); + @modulesNeeded = ($modperlCPAN,$apacheSoapCPAN,'LWP::Simple','Pod::WSDL','Safe','MIME::Base64','File::Which','GD'); @manuallyNeeded = moduleInstaller(@modulesNeeded); $manuallyNeededCount = @manuallyNeeded; |
From: dpvc v. a. <we...@ma...> - 2007-09-26 02:22:36
|
Log Message: ----------- Localize the $ans variable (rather than incorrectly using a closure). Modified Files: -------------- pg/lib/Value: AnswerChecker.pm Revision Data ------------- Index: AnswerChecker.pm =================================================================== RCS file: /webwork/cvs/system/pg/lib/Value/AnswerChecker.pm,v retrieving revision 1.113 retrieving revision 1.114 diff -Llib/Value/AnswerChecker.pm -Llib/Value/AnswerChecker.pm -u -r1.113 -r1.114 --- lib/Value/AnswerChecker.pm +++ lib/Value/AnswerChecker.pm @@ -91,7 +91,7 @@ ); $ans->{debug} = $ans->{rh_ans}{debug}; $ans->install_evaluator(sub { - $ans = shift; + my $ans = shift; $ans->{_filter_name} = "MathObjects answer checker"; $ans->{correct_value}->cmp_parse($ans); }); |
From: Sam H. v. a. <we...@ma...> - 2007-09-25 23:07:25
|
Log Message: ----------- generate a top-level index file listing all PODs Modified Files: -------------- admintools: ww-make-docs Revision Data ------------- Index: ww-make-docs =================================================================== RCS file: /webwork/cvs/system/admintools/ww-make-docs,v retrieving revision 1.3 retrieving revision 1.4 diff -Lww-make-docs -Lww-make-docs -u -r1.3 -r1.4 --- ww-make-docs +++ ww-make-docs @@ -5,75 +5,176 @@ package WeBWorK::Utils::HTMLDocs; -use Pod::Find qw(pod_find); +use File::Find; +use IO::File; +use Pod::Find qw(pod_find simplify_name); use Pod::Html; +use POSIX qw(strftime); +use Data::Dumper; + +our @sections = ( + bin => "Scripts", + conf => "Config Files", + doc => "Documentation", + lib => "Libraries", + macros => "Macros", +); sub new { - my $invocant = shift; + my ($invocant, %o) = @_; my $class = ref $invocant || $invocant; - return bless { @_ }, $class; + + my @section_list = exists $o{sections} ? @{$o{sections}} : @sections; + my $section_hash = {@section_list}; + my $section_order = [ map { $section_list[2*$_] } 0..$#section_list/2 ]; + delete $o{sections}; + + my $self = { + %o, + idx => {}, + section_hash => $section_hash, + section_order => $section_order, + }; + #print Dumper($self); + return bless $self, $class; } sub convert_pods { my $self = shift; my $source_root = $self->{source_root}; - my $subdirs = do { + my $dest_root = $self->{dest_root}; + my @subdirs = do { my $dh; opendir $dh, $source_root; - join ':', - grep { not (/^\./ or /^(CVS|.svn)$/) and -d "$source_root/$_" } - readdir $dh; - }; + grep { not (/^\./ or /^(CVS|.svn)$/) and -d "$source_root/$_" } + readdir $dh; + }; + my $subdirs = join(':', @subdirs); my %pods = pod_find({}, $source_root); while (my ($pod_path, $pod_name) = each %pods) { $self->process_pod($subdirs, $pod_path, $pod_name); } + $self->write_index("$dest_root/index.html"); } sub process_pod { - my ($self, $subdirs, $pod_path, $pod_name) = @_; + my ($self, $subdirs, $pod_path) = @_; my $source_root = $self->{source_root}; my $dest_root = $self->{dest_root}; my $dest_url = $self->{dest_url}; + my $pod_name; + my ($subdir, $filename) = $pod_path =~ m|^$source_root/(?:(.*)/)?(.*)$|; - if ($filename =~ /\.pl$/) { + my $subdir_rest; + if (defined $subdir and $subdir =~ m|/|) { + ($subdir_rest) = $subdir =~ m|^[^/]*/(.*)|; + } + if ($filename =~ /\.plx?$/ or $filename !~ /\./) { + $pod_name = $filename; $filename .= '.html'; } elsif ($filename =~ /\.pod$/) { + $pod_name = $filename; + $pod_name =~ s/\.pod$//; $filename =~ s/\.pod$/.html/; } elsif ($filename =~ /\.pm$/) { + $pod_name = defined $subdir_rest ? "$subdir_rest/" : ""; + $pod_name .= $filename; + $pod_name =~ s/\.pm$//; + $pod_name =~ s|/+|::|g; $filename =~ s/\.pm$/.html/; } my $html_dir = defined $subdir ? "$dest_root/$subdir" : $dest_root; my $html_path = "$html_dir/$filename"; + my $html_rel_path = defined $subdir ? "$subdir/$filename" : $filename; - #print "$pod_path -- $pod_name\n"; - #print " subdir=$subdir\n"; - #print " html_dir=$html_dir\n"; - #print " html_path=$html_path\n"; + #print "$pod_path - $pod_name\n"; + $self->update_index($subdir, $html_rel_path, $pod_name); + do_mkdir($html_dir); + do_pod2html( + subdirs => $subdirs, + source_root => $source_root, + dest_root => $dest_root, + dest_url => $dest_url, + pod_path => $pod_path, + html_path => $html_path, + ); +} + +sub update_index { + my ($self, $subdir, $html_rel_path, $pod_name) = @_; + $subdir =~ s|/.*$||; + my $idx = $self->{idx}; + my $sections = $self->{section_hash}; + if (exists $sections->{$subdir}) { + push @{$idx->{$subdir}}, [ $html_rel_path, $pod_name ]; + } else { + warn "no section for subdir '$subdir'\n"; + } +} + +sub write_index { + my ($self, $out_path) = @_; + my $idx = $self->{idx}; + my $sections = $self->{section_hash}; + my $section_order = $self->{section_order}; + my $source_root = $self->{source_root}; + $source_root =~ s|^.*/||; + + #print Dumper($idx); + + my $header = "<html><head><title>Index $source_root</title></head><body>\n"; + my $content_start = "<h1>Index for $source_root</h1><ul>\n"; + my $content = ""; + + foreach my $section (@$section_order) { + next unless defined $idx->{$section}; + my $section_name = $sections->{$section}; + $content_start .= "<li><a href=\"#$section\">$section_name</a></li>\n"; + my @files = sort @{$idx->{$section}}; + $content .= "<h2><a name=\"$section\">$section_name</a></h2><ul>\n"; + foreach my $file (sort { $a->[1] cmp $b->[1] } @files) { + my ($path, $name) = @$file; + $content .= "<li><a href=\"$path\">$name</a></li>\n"; + } + $content .= "</ul><hr/>\n"; + } - system '/bin/mkdir', '-p', $html_dir; + $content_start .= "</ul><hr/>\n"; + my $date = strftime "%a %b %e %H:%M:%S %Z %Y", localtime; + my $content_end = "<p>Generated $date</p>\n"; + my $footer = "</body></html>\n"; + + my $fh = new IO::File($out_path, 'w') or die "Failed to open index '$out_path' for writing: $!\n"; + print $fh $header, $content_start, $content, $content_end, $footer; +} + +sub do_mkdir { + my $dir = shift; + system '/bin/mkdir', '-p', $dir; if ($?) { my $exit = $? >> 8; my $signal = $? & 127; my $core = $? & 128; - die "/bin/mkdir -p $html_dir failed (exit=$exit signal=$signal core=$core)\n"; + die "/bin/mkdir -p $dir failed (exit=$exit signal=$signal core=$core)\n"; } - - #print join(" ", - pod2html( - defined $subdirs && length $subdirs ? "--podpath=$subdirs" : (), - "--podroot=$source_root", - "--htmldir=$dest_root", - defined $dest_url && length $dest_url ? "--htmlroot=$dest_url" : (), - "--infile=$pod_path", - "--outfile=$html_path", +} + +sub do_pod2html { + my %o = @_; + my @args = ( + defined $o{subdirs} && length $o{subdirs} ? "--podpath=$o{subdirs}" : (), + "--podroot=$o{source_root}", + "--htmldir=$o{dest_root}", + defined $o{dest_url} && length $o{dest_url} ? "--htmlroot=$o{dest_url}" : (), + "--infile=$o{pod_path}", + "--outfile=$o{html_path}", '--recurse', '--header', ); - #), "\n"; - #exit; + #print join(" ", 'pod2html', @args), "\n"; + pod2html(@args); } package main; |
From: Sam H. v. a. <we...@ma...> - 2007-09-25 17:50:52
|
Log Message: ----------- don't pass --subdirs is there are no subdirectories to search Modified Files: -------------- admintools: ww-make-docs Revision Data ------------- Index: ww-make-docs =================================================================== RCS file: /webwork/cvs/system/admintools/ww-make-docs,v retrieving revision 1.2 retrieving revision 1.3 diff -Lww-make-docs -Lww-make-docs -u -r1.2 -r1.3 --- ww-make-docs +++ ww-make-docs @@ -63,7 +63,7 @@ #print join(" ", pod2html( - "--podpath=$subdirs", + defined $subdirs && length $subdirs ? "--podpath=$subdirs" : (), "--podroot=$source_root", "--htmldir=$dest_root", defined $dest_url && length $dest_url ? "--htmlroot=$dest_url" : (), |
From: Sam H. v. a. <we...@ma...> - 2007-09-25 17:49:16
|
Log Message: ----------- handle files that are not in a subdirectory of the source root dir Modified Files: -------------- admintools: ww-make-docs Revision Data ------------- Index: ww-make-docs =================================================================== RCS file: /webwork/cvs/system/admintools/ww-make-docs,v retrieving revision 1.1 retrieving revision 1.2 diff -Lww-make-docs -Lww-make-docs -u -r1.1 -r1.2 --- ww-make-docs +++ ww-make-docs @@ -37,7 +37,7 @@ my $dest_root = $self->{dest_root}; my $dest_url = $self->{dest_url}; - my ($subdir, $filename) = $pod_path =~ m|^$source_root/(.*)/(.*)$|; + my ($subdir, $filename) = $pod_path =~ m|^$source_root/(?:(.*)/)?(.*)$|; if ($filename =~ /\.pl$/) { $filename .= '.html'; } elsif ($filename =~ /\.pod$/) { @@ -45,7 +45,7 @@ } elsif ($filename =~ /\.pm$/) { $filename =~ s/\.pm$/.html/; } - my $html_dir = "$dest_root/$subdir"; + my $html_dir = defined $subdir ? "$dest_root/$subdir" : $dest_root; my $html_path = "$html_dir/$filename"; #print "$pod_path -- $pod_name\n"; |
From: Sam H. v. a. <we...@ma...> - 2007-09-25 17:39:34
|
Log Message: ----------- re-set path to work on devel Modified Files: -------------- admintools: ww-make-docs-from-cvs Revision Data ------------- Index: ww-make-docs-from-cvs =================================================================== RCS file: /webwork/cvs/system/admintools/ww-make-docs-from-cvs,v retrieving revision 1.1 retrieving revision 1.2 diff -Lww-make-docs-from-cvs -Lww-make-docs-from-cvs -u -r1.1 -r1.2 --- ww-make-docs-from-cvs +++ ww-make-docs-from-cvs @@ -32,7 +32,7 @@ our $CVS = "/usr/bin/cvs"; our $MKDIR = "/bin/mkdir"; -our $WW_MAKE_DOCS = '/home/sam/work/admintools/ww-make-docs'; +our $WW_MAKE_DOCS = '/home/sh002i/work/admintools/ww-make-docs'; our $v; # for verbose switch |
From: Sam H. v. a. <we...@ma...> - 2007-09-25 16:59:37
|
Log Message: ----------- utility to check out sources from CVS and generate HTML from POD. Added Files: ----------- admintools: ww-make-docs-from-cvs Revision Data ------------- --- /dev/null +++ ww-make-docs-from-cvs @@ -0,0 +1,85 @@ +#!/usr/bin/perl -sT +################################################################################ +# WeBWorK Online Homework Delivery System +# Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/ +# $CVSHeader: admintools/ww-make-docs-from-cvs,v 1.1 2007/09/25 16:52:33 sh002i Exp $ +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of either: (a) the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version, or (b) the "Artistic License" which comes with this package. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the +# Artistic License for more details. +################################################################################ + +=head1 NAME + +ww-make-docs-from-cvs - make WeBWorK documentation from CVS viewable over the web + +=cut + +use strict; +use warnings; + +$ENV{PATH} = ""; +$ENV{ENV} = ""; + +our $CHECKOUT_DIR = '/webwork/docs2html'; +our $DOC_DIR = '/webwork/www/main/doc/cvs'; + +our $CVS = "/usr/bin/cvs"; +our $MKDIR = "/bin/mkdir"; +our $WW_MAKE_DOCS = '/home/sam/work/admintools/ww-make-docs'; + +our $v; # for verbose switch + +my @dirs; + +if (@ARGV) { + @dirs = map "$CHECKOUT_DIR/$_", @ARGV; +} else { + @dirs = glob("$CHECKOUT_DIR/*"); +} + +foreach my $dir (@dirs) { + next unless -d $dir; + if ($dir =~ m/^([^\!\$\^\&\*\(\)\~\[\]\|\{\}\'\"\;\<\>\?]+)$/) { + print "\n-----> $dir <-----\n\n" if $v; + update_cvs($1); + process_dir($1); + } else { + warn "'$dir' insecure.\n"; + } +} + +sub update_cvs { + my ($dir) = @_; + + system "cd \"$dir\" && $CVS -q update -dP" and die "cvs failed: $!\n"; +} + +sub process_dir { + my ($source_dir) = @_; + my $dest_dir = $source_dir; + $dest_dir =~ s/^$CHECKOUT_DIR/$DOC_DIR/; + + system $MKDIR, '-p', $dest_dir; + if ($?) { + my $exit = $? >> 8; + my $signal = $? & 127; + my $core = $? & 128; + die "/bin/mkdir -p $dest_dir failed (exit=$exit signal=$signal core=$core)\n"; + } + + system $WW_MAKE_DOCS, $source_dir, $dest_dir; + if ($?) { + my $exit = $? >> 8; + my $signal = $? & 127; + my $core = $? & 128; + die "$WW_MAKE_DOCS $source_dir $dest_dir failed (exit=$exit signal=$signal core=$core)\n"; + } +} + |
From: Sam H. v. a. <we...@ma...> - 2007-09-25 16:56:29
|
Log Message: ----------- utility to convert a tree of POD docs into HTML. unlike wwdocs2html, this program enables linking between files. Added Files: ----------- admintools: ww-make-docs Revision Data ------------- --- /dev/null +++ ww-make-docs @@ -0,0 +1,95 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +package WeBWorK::Utils::HTMLDocs; + +use Pod::Find qw(pod_find); +use Pod::Html; + +sub new { + my $invocant = shift; + my $class = ref $invocant || $invocant; + return bless { @_ }, $class; +} + +sub convert_pods { + my $self = shift; + my $source_root = $self->{source_root}; + my $subdirs = do { + my $dh; + opendir $dh, $source_root; + join ':', + grep { not (/^\./ or /^(CVS|.svn)$/) and -d "$source_root/$_" } + readdir $dh; + }; + + my %pods = pod_find({}, $source_root); + while (my ($pod_path, $pod_name) = each %pods) { + $self->process_pod($subdirs, $pod_path, $pod_name); + } +} + +sub process_pod { + my ($self, $subdirs, $pod_path, $pod_name) = @_; + my $source_root = $self->{source_root}; + my $dest_root = $self->{dest_root}; + my $dest_url = $self->{dest_url}; + + my ($subdir, $filename) = $pod_path =~ m|^$source_root/(.*)/(.*)$|; + if ($filename =~ /\.pl$/) { + $filename .= '.html'; + } elsif ($filename =~ /\.pod$/) { + $filename =~ s/\.pod$/.html/; + } elsif ($filename =~ /\.pm$/) { + $filename =~ s/\.pm$/.html/; + } + my $html_dir = "$dest_root/$subdir"; + my $html_path = "$html_dir/$filename"; + + #print "$pod_path -- $pod_name\n"; + #print " subdir=$subdir\n"; + #print " html_dir=$html_dir\n"; + #print " html_path=$html_path\n"; + + system '/bin/mkdir', '-p', $html_dir; + if ($?) { + my $exit = $? >> 8; + my $signal = $? & 127; + my $core = $? & 128; + die "/bin/mkdir -p $html_dir failed (exit=$exit signal=$signal core=$core)\n"; + } + + #print join(" ", + pod2html( + "--podpath=$subdirs", + "--podroot=$source_root", + "--htmldir=$dest_root", + defined $dest_url && length $dest_url ? "--htmlroot=$dest_url" : (), + "--infile=$pod_path", + "--outfile=$html_path", + '--recurse', + '--header', + ); + #), "\n"; + #exit; +} + +package main; + +unless (caller) { + unless (@ARGV >= 2) { + print "usage: $0 source_root dest_root [ dest_url ]\n"; + exit 1; + } + my $htmldocs = new WeBWorK::Utils::HTMLDocs( + source_root => $ARGV[0], + dest_root => $ARGV[1], + dest_url => $ARGV[2], + ); + $htmldocs->convert_pods; +} + +1; + |
From: Matt L. v. a. <we...@ma...> - 2007-09-25 02:30:40
|
Log Message: ----------- New config Modified Files: -------------- wwmoodle/wwassignment3/moodle/blocks/wwlink: config_instance.html Revision Data ------------- Index: config_instance.html =================================================================== RCS file: /webwork/cvs/system/wwmoodle/wwassignment3/moodle/blocks/wwlink/config_instance.html,v retrieving revision 1.2 retrieving revision 1.3 diff -Lwwassignment3/moodle/blocks/wwlink/config_instance.html -Lwwassignment3/moodle/blocks/wwlink/config_instance.html -u -r1.2 -r1.3 --- wwassignment3/moodle/blocks/wwlink/config_instance.html +++ wwassignment3/moodle/blocks/wwlink/config_instance.html @@ -1,6 +1,6 @@ <?php global $CFG; - $lib = $CFG->wwwroot . '/mod/wwassignment/locallib.php'; + $lib = $CFG->dirroot . '/mod/wwassignment/locallib.php'; ?> <table cellpadding="9" cellspacing="0" align="center"> <?php if(!file_exists($lib)) { ?> |