Skip to content

Commit 2c964c2

Browse files
committed
WIP: rearrange the OPL macros for clarity
1 parent 0cf5795 commit 2c964c2

File tree

6 files changed

+1713
-0
lines changed

6 files changed

+1713
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,369 @@
1+
# A group of macros used in the Alfred problem library.
2+
3+
sub _Alfredmacros_init {} #don't reload these macros.
4+
5+
6+
# Given a point (x,y) this macro computes the angle with respect to x-axis. The angle will be between 0 and 2pi.
7+
sub inversetrig
8+
{my $refangle = arctan(abs($_[1]/$_[0]));
9+
if($_[0] == 0)
10+
{0}
11+
elsif ($_[0]>0)
12+
{if($_[1] == 0)
13+
{0}
14+
elsif($_[1]>0)
15+
{$refangle;}
16+
else
17+
{2*pi-$refangle;}
18+
}
19+
else
20+
{if($_[1] == 0)
21+
{pi}
22+
elsif($_[1]>0)
23+
{pi-$refangle;}
24+
else
25+
{pi+$refangle}
26+
}
27+
}
28+
29+
## Compute the max and min of an array of numbers
30+
31+
32+
33+
#This macro prevents students from double clicking in an answer box. This macro #is necessary for multiple integral problems where the answer box is typeset
34+
#into the integration symbols.
35+
sub doubleclickprevent
36+
{TEXT(MODES(
37+
TeX => "",
38+
HTML => "<SCRIPT>if (window.jsMath) {jsMath.Click.DblClick = function () {}}</SCRIPT>"
39+
));
40+
}
41+
42+
#The problems that have the answer box in the limits must be displayed in JS
43+
#math mode. This macro warns the user to use JS math mode if they are not.
44+
sub jsMathwarn
45+
{TEXT(MODES(
46+
TeX => '',
47+
HTML_jsMath => '',
48+
HTML => $HR."Warning: to use this problem, you need to".
49+
"select jsMath mode in the Display Options panel at the left".$HR,
50+
));
51+
}
52+
53+
sub jsmathmode
54+
{
55+
TEXT(MODES(
56+
TeX => '',
57+
HTML_jsMath => '',
58+
HTML => $HR."Warning: to use this problem, you need to ".
59+
"select jsMath mode in the Display Options panel at the left".$HR,
60+
));
61+
TEXT(MODES(
62+
TeX => "",
63+
HTML => "<SCRIPT>if (window.jsMath) {jsMath.Click.DblClick = function () {}}</SCRIPT>"
64+
));
65+
66+
}
67+
68+
sub mathjaxmode
69+
{TEXT(MODES(
70+
TeX => '',
71+
HTML_MathJax => '',
72+
HTML => $HR."Warning: to use this problem, you need to ".
73+
"select MathJax mode in the Display Options panel at the left".$HR,
74+
));
75+
}
76+
77+
#This subroutine includes the Strang's textbook into a problem, you have to
78+
#feed it the chapter and section. It is assumed that the book is in the course
79+
#directory and is labeled strangtextbook. The parameters are
80+
#strang(chapter,section,(optional) section title.
81+
#example \{&strang(16,5,"surface integrals")\}.
82+
$wwstrang = "http://webwork.alfred.edu/webwork2_course_files/strangcalculus";
83+
sub strang
84+
{
85+
htmlLink(qq!$wwstrang/Strang-$_[0]-$_[1].pdf!,"$_[0].$_[1] $_[2] from Gilbert Strang's Calculus",q/TARGET="new_window"/)
86+
}
87+
88+
#Inserts a link to a trig table in the problem.
89+
#example \{&trig_table()\}
90+
sub trig_table
91+
{
92+
htmlLink(qq!$wwstrang/trig_identities.pdf!,"Trig Identities",q/TARGET="new_window"/)
93+
}
94+
95+
sub strang_index
96+
{
97+
htmlLink(qq!$wwstrang/Index.pdf!,"Index",q/TARGET="new_window"/)
98+
}
99+
100+
sub strang_TOC
101+
{
102+
htmlLink(qq!$wwstrang/TOC.pdf!,"Table of Contents",q/TARGET="new_window"/)
103+
}
104+
105+
sub product_Rule_cmp {
106+
my ( $correct, $student, $self ) = @_;
107+
my ( $f1stu, $f2stu,$f3stu,$f4stu ) = @{$student};
108+
my ( $f1, $f2, $f3, $f4 ) = @{$correct};
109+
my @fgrade = (0,0,0,0);
110+
my @fstu = ($f1stu,$f2stu,$f3stu,$f4stu);
111+
my @fcorrect = ($f1,$f2,$f3,$f4);
112+
#we will associate each student answer with a prime number, noting which student answer is in which blank. This allows us to make use of the fundamental theorem of arithmetic.
113+
my @prime = (2,3,5,7);
114+
my @answerblank = (0,0,0,0);
115+
116+
for($i=0;$i<4;$i++){
117+
for($j=0;$j<4;$j++){
118+
if(($fcorrect[$i]==$fstu[$j])&&($answerblank[$j]==0)){
119+
{$answerblank[$j] = $prime[$i];
120+
$j = 4 # you have to terminate the inner loop in this case for the special case of f=e^x where f and f' are the same.
121+
}
122+
}
123+
}
124+
};
125+
for($i=0;$i<4;$i++){
126+
if(!$answerblank[$i]){
127+
$self->setMessage($i+1,"All of your answers should be $f, $g, or a derivative of one of these functions");
128+
}
129+
}
130+
#now we rely on the fact that products of primes are unique. First we check to see if all of the blanks are correct
131+
if ((($answerblank[0]*$answerblank[1] == 6)&&($answerblank[2]*$answerblank[3] == 35))||(($answerblank[0]*$answerblank[1] == 35)&&($answerblank[2]*$answerblank[3] == 6))){
132+
@fgrade = (1,1,1,1);
133+
}
134+
#now check to see if the first pair of blanks is correct, knowing one pair is not
135+
elsif ($answerblank[0]*$answerblank[1] == 6){
136+
if (($answerblank[2] == 5)||($answerblank[2] == 7)){
137+
@fgrade = (1,1,1,0);
138+
}
139+
elsif (($answerblank[3] == 5)||($answerblank[3] == 7)){
140+
@fgrade = (1,1,0,1);
141+
}
142+
else {@fgrade = (1,1,0,0);}
143+
}
144+
elsif ($answerblank[0]*$answerblank[1] == 35){
145+
if (($answerblank[2] == 2)||($answerblank[2] == 3)){
146+
@fgrade = (1,1,1,0);
147+
}
148+
elsif (($answerblank[3] == 2)||($answerblank[3] == 3)){
149+
@fgrade = (1,1,0,1);
150+
}
151+
else {@fgrade = (1,1,0,0);}
152+
}
153+
#if both sets are not correct, and the first set is not correct, check to see if the last pair are
154+
elsif ($answerblank[2]*$answerblank[3] == 6){
155+
if (($answerblank[0] == 5)||($answerblank[0] == 7)){
156+
@fgrade = (1,0,1,1);
157+
}
158+
elsif (($answerblank[1] == 5)||($answerblank[1] == 7)){
159+
@fgrade = (0,1,1,1);
160+
}
161+
else {@fgrade = (0,0,1,1);}
162+
}
163+
elsif ($answerblank[2]*$answerblank[3] == 35){
164+
if (($answerblank[0] == 2)||($answerblank[0] == 3)){
165+
@fgrade = (1,0,1,1);
166+
}
167+
elsif (($answerblank[1] == 2)||($answerblank[1] == 3)){
168+
@fgrade = (0,1,1,1);
169+
}
170+
else {@fgrade = (0,0,1,1);}
171+
}
172+
#at this point they don't have a matched set of blanks correct. look for a single function in each pair that is right. You have to make sure you only get one for each pair of answer blanks.
173+
else{
174+
if (($answerblank[0])&&($answerblank[2])&&($answerblank[0]*$answerblank[2] !=6)&&($answerblank[0]*$answerblank[2] !=35)&&($answerblank[0]!=$answerblank[2])){
175+
@fgrade = (1,0,1,0);
176+
}
177+
elsif (($answerblank[0])&&($answerblank[3])&&($answerblank[0]*$answerblank[3] !=6)&&($answerblank[0]*$answerblank[3] !=35)&&($answerblank[0]!=$answerblank[3])){
178+
@fgrade = (1,0,0,1);
179+
}
180+
elsif (($answerblank[1])&&($answerblank[2])&&($answerblank[1]*$answerblank[2] !=6)&&($answerblank[1]*$answerblank[2] !=35)&&($answerblank[1]!=$answerblank[2])){
181+
@fgrade = (0,1,1,0);
182+
}
183+
elsif (($answerblank[1])&&($answerblank[3])&&($answerblank[1]*$answerblank[3] !=6)&&($answerblank[1]*$answerblank[3] !=35)&&($answerblank[1]!=$answerblank[3])){
184+
@fgrade = (0,1,0,1);
185+
}
186+
elsif ($answerblank[0]){@fgrade = (1,0,0,0)}
187+
elsif ($answerblank[1]){@fgrade = (0,1,0,0)}
188+
elsif ($answerblank[2]){@fgrade = (0,0,1,0)}
189+
elsif ($answerblank[3]){@fgrade = (0,0,0,1)}
190+
};
191+
return [@fgrade];
192+
}
193+
194+
195+
196+
sub check_boundary_conditions {
197+
my ( $correct, $student, $self ) = @_;
198+
return product_Rule_cmp(@_) ;
199+
}
200+
201+
sub Snxy(){
202+
my %args = @_;
203+
my @x = @{$args{inputs}};
204+
my @y = @{$args{outputs}};
205+
my $m = $args{m};
206+
my $n = $args{n};
207+
my $i = 0;
208+
my $sum = 0;
209+
if ($#x == $#y){
210+
for ($i=0;$i <= $#x;$i++){
211+
$sum = $sum + ($x[$i])**($n)*($y[$i])**($m);
212+
}
213+
}
214+
else {$sum = 0};
215+
return $sum;
216+
}
217+
218+
### To use the macros your problem must include unionTables.pl, and of course Alfredmacros.pl
219+
### Table integral returns a string that can be included in a Table to output an integral whose upper and lower limits
220+
### of integration can be answer blanks. There are several optional parameters:
221+
### width - change the width of the answer blanks. defaults to 3.
222+
### lowerwidth - change the width of the lower answer blank. defaults to width
223+
### upperwidth - change the width of the upper answer blank. defaults to width.
224+
### upper - the uppper limit of integration, does not have to be an answer blank, defaults to answer blank with width "width"
225+
### lower - the lower limit of integration, does not have to be an answer blank, defaults to answer blank with width "width"
226+
### limits - boolean, if 1 puts the limits of integration above and below the integral symbol, if 0 puts them after the integral symbol.
227+
### default is 1.
228+
### Your code must include unionTables.pl, and of course Alfredmacros.pl
229+
### An example:
230+
### \{BeginTable(center=>0).
231+
### Row([tableintegral(),
232+
### ],separation=>2).
233+
### EndTable();
234+
### \}
235+
### which will print an integral with answer blank on the upper and lower limits with the default length of 3
236+
###
237+
### This example prints out a double integral, the first integral with answer blanks with width 10, the second integral
238+
### has 0 for the lower limit of integration and an answer blank with width 5 for the upper limit of integration.
239+
### The default limits of integratin are answer blanks with width 3, in this case the default width was overridden to 5
240+
### and the default lower limit was changed to a zero.
241+
### \{BeginTable(center=>0).
242+
### Row([tableintegral(width=>10,limits=>'\(0\)'),tableintegral(width=>5,lower=>'\(0\)',limits=>0),
243+
### ],separation=>2).
244+
### EndTable();
245+
### \}
246+
### An example where the width of the upper and lower answer blanks have different widths.
247+
### \{BeginTable(center=>0).
248+
### Row([tableintegral(lowerwidth=>10,upperwidth=>1)
249+
### ],separation=>2).
250+
### EndTable();
251+
### \}
252+
253+
sub tableintegral{
254+
my %arg = @_;
255+
my $width = delete $arg{width} // 3;
256+
my $lowerwidth = delete $arg{lowerwidth} // $width;
257+
my $upperwidth = delete $arg{upperwidth} // $width;
258+
my $lower = delete $arg{lower} // ans_rule($lowerwidth);
259+
my $upper = delete $arg{upper} // ans_rule($upperwidth);
260+
my $limits = delete $arg{limits} // 1;
261+
if ($limits == 1){
262+
return $upper.$BR.'\(\displaystyle\int\)'.$BR.$lower
263+
}
264+
else {
265+
return '\(\displaystyle\int\)',$upper.$BR.$BR.$lower
266+
}
267+
};
268+
269+
# a sum with answer blanks for the summation variable, lower limit, and upper limit
270+
#\{ BeginTable(center=>0).
271+
# Row([tablesum(width=>10),
272+
# ],separation=>2).
273+
# EndTable();
274+
#\}
275+
# a sum with answer blanks for the upper and lower limits, and the summation variable is i
276+
#\{ BeginTable(center=>0).
277+
# Row([tablesum(width=>10,sumvariable=>'i'),
278+
# ],separation=>2).
279+
# EndTable();
280+
#\}
281+
# a sum with answer blanks for the upper and lower limits, and summation variable is not used.
282+
#\{ BeginTable(center=>0).
283+
# Row([tablesum(width=>10,usesumvariable=>0),
284+
# ],separation=>2).
285+
# EndTable();
286+
#\}
287+
# sum from n = 1 to infinity
288+
#\{ BeginTable(center=>0).
289+
# Row([tablesum(sumvariable=>'\(n\)',lower=>'\(1\)', upper=>'\(\hskip 3pt\infty\)') ],separation=>2).
290+
# EndTable();
291+
#\}
292+
293+
sub tablesum{
294+
my %arg = @_;
295+
my $width = delete $arg{width} // 3;
296+
my $lowerwidth = delete $arg{lowerwidth} // $width;
297+
my $upperwidth = delete $arg{upperwidth} // $width;
298+
my $lower = delete $arg{lower} // ans_rule($lowerwidth);
299+
my $upper = delete $arg{upper} // ans_rule($upperwidth);
300+
my $limits = delete $arg{limits} // 1;
301+
my $sumvariable = delete $arg{sumvariable} // ans_rule($width);
302+
my $usesumvariable = delete $arg{usesumvariable} // 1;
303+
if ($usesumvariable == 0){
304+
if ($limits == 1){
305+
return $upper.$BR.'\(\displaystyle\sum\)'.$BR.$lower
306+
}
307+
else {
308+
return '\(\displaystyle\int\)',$upper.$BR.$BR.$lower
309+
}
310+
}
311+
else {
312+
if ($limits == 1){
313+
return $upper.$BR.'\(\displaystyle\sum\)'.$BR.$sumvariable.'\( = \)'.$lower
314+
}
315+
else {
316+
return '\(\displaystyle\int\)',$upper.$BR.$BR.$sumvariable.'\( = \)'.$lower
317+
}
318+
}
319+
};
320+
321+
322+
### Create a vertical bar with an upper and lower limit.
323+
sub tableevaluate{
324+
my %arg = @_;
325+
my $width = delete $arg{width} // 3;
326+
my $lowerwidth = delete $arg{lowerwidth} // $width;
327+
my $upperwidth = delete $arg{upperwidth} // $width;
328+
my $lower = delete $arg{lower} // ans_rule($lowerwidth);
329+
my $upper = delete $arg{upper} // ans_rule($upperwidth);
330+
return
331+
'\(\Bigg\vert\)',$upper.$BR.$BR.$lower
332+
};
333+
334+
### Create a subscripted character
335+
sub tablesubscript{
336+
my %arg = @_;
337+
my $width = delete $arg{width} // 3;
338+
my $lower = delete $arg{lower} // ans_rule($width);
339+
my $variable = delete $arg{variable} // 'c';
340+
return
341+
$variable,$BR.$BR.$lower
342+
};
343+
344+
### Create a superscripted character
345+
sub tablesuperscript{
346+
my %arg = @_;
347+
my $width = delete $arg{width} // 3;
348+
my $upper = delete $arg{upper} // ans_rule($width);
349+
my $variable = delete $arg{variable} // 'c';
350+
return
351+
$variable,$upper.$BR.$BR.$BR
352+
};
353+
354+
355+
356+
### A fraction
357+
sub tablefrac{
358+
my %arg = @_;
359+
my $width = delete $arg{width} // 3;
360+
my $lower = delete $arg{lower} // ans_rule($width);
361+
my $upper = delete $arg{upper} // ans_rule($width);
362+
my $barwidth = delete $arg{barwidth} // 10+$width;
363+
my $divisionbar = "";
364+
for ($count = 1;$count <= $barwidth; $count++){
365+
$divisionbar = $divisionbar."-";
366+
}
367+
return $upper.$BR.$divisionbar.$BR.$lower
368+
};
369+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# this file defines all Brock-Physics-specific macros.

0 commit comments

Comments
 (0)