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

Annotation of /trunk/pg/macros/PGmatrixmacros.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1097 - (view) (download) (as text)

1 : sh002i 1050
2 : apizer 1080
3 : sh002i 1050 ###########
4 :     #use Carp;
5 :    
6 :     =head1 NAME
7 :    
8 :     Matrix macros for the PG language
9 :    
10 :     =head1 SYNPOSIS
11 :    
12 :    
13 :    
14 :     =head1 DESCRIPTION
15 :    
16 :     Almost all of the macros in the file are very rough at best. The most useful is display_matrix.
17 : jj 1097 Many of the other macros work with vectors and matrices stored as anonymous arrays.
18 : sh002i 1050
19 :     Frequently it may be
20 :     more useful to use the Matrix objects defined RealMatrix.pm and Matrix.pm and the constructs listed there.
21 :    
22 :    
23 :     =cut
24 :    
25 :     BEGIN {
26 :     be_strict();
27 :     }
28 :    
29 :     sub _PGmatrixmacros_init {
30 :     }
31 :    
32 :     # this subroutine zero_check is not very well designed below -- if it is used much it should receive
33 : jj 1097 # more work -- particularly for checking relative tolerance. More work needs to be done if this is
34 : sh002i 1050 # actually used.
35 :    
36 :     sub zero_check{
37 :     my $array = shift;
38 :     my %options = @_;
39 :     my $num = @$array;
40 :     my $i;
41 :     my $max = 0; my $mm;
42 :     for ($i=0; $i< $num; $i++) {
43 :     $mm = $array->[$i] ;
44 :     $max = abs($mm) if abs($mm) > $max;
45 :     }
46 :     my $tol = $options{tol};
47 :     $tol = 0.01*$options{reltol}*$options{avg} if defined($options{reltol}) and defined $options{avg};
48 :     $tol = .000001 unless defined($tol);
49 :     ($max <$tol) ? 1: 0; # 1 if the array is close to zero;
50 :     }
51 :     sub vec_dot{
52 :     my $vec1 = shift;
53 :     my $vec2 = shift;
54 :     warn "vectors must have the same length" unless @$vec1 == @$vec2; # the vectors must have the same length.
55 :     my @vec1=@$vec1;
56 :     my @vec2=@$vec2;
57 :     my $sum = 0;
58 :    
59 :     while(@vec1) {
60 :     $sum += shift(@vec1)*shift(@vec2);
61 :     }
62 :     $sum;
63 :     }
64 :     sub proj_vec {
65 :     my $vec = shift;
66 : jj 1097 warn "First input must be a column matrix" unless ref($vec) eq 'Matrix' and ${$vec->dim()}[1] == 1;
67 :     my $matrix = shift; # the matrix represents a set of vectors spanning the linear space
68 : sh002i 1050 # onto which we want to project the vector.
69 :     warn "Second input must be a matrix" unless ref($matrix) eq 'Matrix' and ${$matrix->dim()}[1] == ${$vec->dim()}[0];
70 :     $matrix * transpose($matrix) * $vec;
71 :     }
72 : jj 1097
73 : sh002i 1050 sub vec_cmp{ #check to see that the submitted vector is a non-zero multiple of the correct vector
74 :     my $correct_vector = shift;
75 :     my %options = @_;
76 :     my $ans_eval = sub {
77 :     my $in = shift @_;
78 : jj 1097
79 : sh002i 1050 my $ans_hash = new AnswerHash;
80 :     my @in = split("\0",$in);
81 : jj 1097 my @correct_vector=@$correct_vector;
82 : sh002i 1050 $ans_hash->{student_ans} = "( " . join(", ", @in ) . " )";
83 :     $ans_hash->{correct_ans} = "( " . join(", ", @correct_vector ) . " )";
84 :    
85 :     return($ans_hash) unless @$correct_vector == @in; # make sure the vectors are the same dimension
86 : jj 1097
87 : sh002i 1050 my $correct_length = vec_dot($correct_vector,$correct_vector);
88 :     my $in_length = vec_dot(\@in,\@in);
89 : jj 1097 return($ans_hash) if $in_length == 0;
90 : sh002i 1050
91 :     if (defined($correct_length) and $correct_length != 0) {
92 :     my $constant = vec_dot($correct_vector,\@in)/$correct_length;
93 :     my @difference = ();
94 :     for(my $i=0; $i < @correct_vector; $i++ ) {
95 :     $difference[$i]=$constant*$correct_vector[$i] - $in[$i];
96 :     }
97 :     $ans_hash->{score} = zero_check(\@difference);
98 : jj 1097
99 : sh002i 1050 } else {
100 :     $ans_hash->{score} = 1 if vec_dot(\@in,\@in) == 0;
101 :     }
102 :     $ans_hash;
103 : jj 1097
104 : sh002i 1050 };
105 : jj 1097
106 : sh002i 1050 $ans_eval;
107 :     }
108 :    
109 :     ############
110 :    
111 :     =head4 display_matrix
112 :    
113 : gage 1066 Usage \{ display_matrix( [ [1, '\(\sin x\)'], [ans_rule(5), 6] ]) \}
114 :     \{ display_matrix($A, align=>'crvl') \}
115 :     \[ \{ display_matrix_mm($A) \} \]
116 :     \[ \{ display_matrix_mm([ [1, 3], [4, 6] ]) \} \]
117 : sh002i 1050
118 : gage 1066 display_matrix produces a matrix for display purposes. It checks whether
119 :     it is producing LaTeX output, or if it is displaying on a web page in one
120 :     of the various modes. The input can either be of type Matrix, or a
121 :     reference to an array.
122 : sh002i 1050
123 : gage 1066 Entries can be numbers, Fraction objects, bits of math mode, or answer
124 :     boxes. An entire row can be replaced by the string 'hline' to produce
125 :     a horizontal line in the matrix.
126 :    
127 :     display_matrix_mm functions similarly, except that it should be inside
128 :     math mode. display_matrix_mm cannot contain answer boxes in its entries.
129 :     Entries to display_matrix_mm should assume that they are already in
130 :     math mode.
131 :    
132 :     Both functions take an optional alignment string, similar to ones in
133 :     LaTeX tabulars and arrays. Here c for centered columns, l for left
134 :     flushed columns, and r for right flushed columns.
135 :    
136 :     The alignment string can also specify vertical rules to be placed in the
137 :     matrix. Here s or | denote a solid line, d is a dashed line, and v
138 :     requests the default vertical line. This can be set on a system-wide
139 :     or course-wide basis via the variable $defaultDisplayMatrixStyle, and
140 :     it can default to solid, dashed, or no vertical line (n for none).
141 :    
142 :     The matrix has left and right delimiters also specified by
143 :     $defaultDisplayMatrixStyle. They can be parentheses, square brackets,
144 :     braces, vertical bars, or none. The default can be overridden in
145 :     an individual problem with optional arguments such as left=>"|", or
146 :     right=>"]".
147 :    
148 :     You can specify an optional argument of 'top_labels'=> ['a', 'b', 'c'].
149 :     These are placed above the columns of the matrix (as is typical for
150 :     linear programming tableaux, for example. The entries will be typeset
151 :     in math mode.
152 :    
153 :     Top labels require a bit of care. For image modes, they look better
154 :     with display_matrix_mm where it is all one big image, but they work with
155 :     display_matrix. With tth, you pretty much have to use display_matrix
156 :     since tth can't handle the TeX tricks used to get the column headers
157 :     up there if it gets the whole matrix at once.
158 :    
159 :    
160 : sh002i 1050 =cut
161 :    
162 :    
163 : jj 1097 sub display_matrix_mm{ # will display a matrix in tex format.
164 : sh002i 1050 # the matrix can be either of type array or type 'Matrix'
165 : gage 1066 return display_matrix(@_, 'force_tex'=>1);
166 :     }
167 :    
168 :     sub display_matrix_math_mode {
169 :     return display_matrix_mm(@_);
170 :     }
171 :    
172 :     sub display_matrix {
173 : sh002i 1050 my $ra_matrix = shift;
174 : gage 1066 my %opts = @_;
175 :     my $styleParams = defined($main::defaultDisplayMatrixStyle) ?
176 :     $main::defaultDisplayMatrixStyle : "(s)";
177 : jj 1097
178 : gage 1066 set_default_options(\%opts,
179 :     '_filter_name' => 'display_matrix',
180 :     'force_tex' => 0,
181 :     'left' => substr($styleParams,0,1),
182 :     'right' => substr($styleParams,2,1),
183 :     'midrule' => substr($styleParams,1,1),
184 :     'top_labels' => 0,
185 : jj 1097 'box'=>0, # pair location of boxed element
186 : gage 1066 'allow_unknown_options'=> 1);
187 : jj 1097
188 : gage 1066 my ($numRows, $numCols, @myRows);
189 :    
190 : sh002i 1050 if (ref($ra_matrix) eq 'Matrix' ) {
191 : gage 1066 ($numRows, $numCols) = $ra_matrix->dim();
192 :     for( my $i=0; $i<$numRows; $i++) {
193 :     $myRows[$i] = [];
194 :     for (my $j=0; $j<$numCols; $j++) {
195 :     my $entry = $ra_matrix->element($i+1,$j+1);
196 :     $entry = "#" unless defined($entry);
197 :     push @{ $myRows[$i] }, $entry;
198 :     }
199 : sh002i 1050 }
200 : jj 1097 } else { # matrix is input as [ [1,2,3],[4,5,6]]
201 : gage 1066 $numCols = 0;
202 :     @myRows = @{$ra_matrix};
203 :     $numRows = scalar(@myRows); # counts horizontal rules too
204 :     my $tmp;
205 :     for $tmp (@myRows) {
206 :     if($tmp ne 'hline') {
207 :     my @arow = @{$tmp};
208 :     $numCols= scalar(@arow); #number of columns in table
209 :     last;
210 :     }
211 : sh002i 1050 }
212 : gage 1066 }
213 : jj 1097 my ($boxrow,$boxcol) = (-1,-1); #default to impossible values so nothing is boxed
214 :     if($opts{'box'}) {
215 :     $boxrow = $opts{'box'}->[0];
216 :     $boxcol = $opts{'box'}->[1];
217 :     }
218 :    
219 :    
220 : gage 1066 my $out;
221 :     my $j;
222 :     my $alignString=''; # alignment as a string for dvi/pdf
223 :     my $alignList; # alignment as a list
224 :    
225 :     if(defined($opts{'align'})) {
226 :     $alignString= $opts{'align'};
227 :     $alignString =~ s/v/$opts{'midrule'}/g;
228 :     $alignString =~ tr/s/|/; # Treat "s" as "|"
229 :     $alignString =~ tr/n//; # Remove "n" altogether
230 :     @$alignList = split //, $alignString;
231 : sh002i 1050 } else {
232 : gage 1066 for($j=0; $j<$numCols; $j++) {
233 :     $alignList->[$j] = "c";
234 :     $alignString .= "c";
235 :     }
236 : sh002i 1050 }
237 : jj 1097 # Before we start, we cannot let top_labels proceed if we
238 :     # are in tth mode and force_tex is true since tth can't handle
239 :     # the resulting code
240 :     if($opts{'force_tex'} and $main::displayMode eq 'HTML_tth') {
241 :     $opts{'top_labels'} = 0;
242 :     }
243 : gage 1066
244 :     $out .= dm_begin_matrix($alignString, %opts);
245 :     # column labels for linear programming
246 :     $out .= dm_special_tops(%opts) if ($opts{'top_labels'});
247 :     $out .= dm_mat_left($numRows, %opts);
248 :     # vertical lines put in with first row
249 :     $j = shift @myRows;
250 :     $out .= dm_mat_row($j, $alignList, %opts, 'isfirst'=>$numRows);
251 :     $out .= dm_mat_right($numRows, %opts);
252 :     for $j (@myRows) {
253 :     $out .= dm_mat_row($j, $alignList, %opts, 'isfirst'=>0);
254 :     }
255 :     $out .= dm_end_matrix(%opts);
256 : sh002i 1050 $out;
257 :     }
258 :    
259 : gage 1066 sub dm_begin_matrix {
260 :     my ($aligns)=shift; #alignments of columns in table
261 :     my %opts = @_;
262 :     my $out = "";
263 :     if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
264 :     # This should be doable by regexp, but it wasn't working for me
265 :     my ($j, @tmp);
266 :     @tmp = split //, $aligns;
267 :     $aligns='';
268 :     for $j (@tmp) {
269 :     # I still can't get an @ expression sent to TeX, so plain
270 :     # vertical line
271 :     $aligns .= ($j eq "d") ? '|' : $j;
272 :     }
273 :     $out .= $opts{'force_tex'} ? '' : '\(';
274 :     if($opts{'top_labels'}) {
275 :     $out .= '\begingroup\setbox3=\hbox{\ensuremath{';
276 :     }
277 :     $out .= '\displaystyle\left'.$opts{'left'}."\\begin{array}{$aligns} \n";
278 :     } elsif ($main::displayMode eq 'Latex2HTML') {
279 :     $out .= "\n\\begin{rawhtml} <TABLE BORDER=0>\n\\end{rawhtml}";
280 :     } elsif ($main::displayMode eq 'HTML' or $main::displayMode eq 'HTML_tth'
281 :     or $main::displayMode eq 'HTML_dpng'
282 :     or $main::displayMode eq 'HTML_img') {
283 :     $out .= qq!<TABLE BORDER="0" Cellspacing="8">\n!;
284 :     }
285 : jj 1097 else {
286 : gage 1066 $out = "Error: dm_begin_matrix: Unknown displayMode: $main::displayMode.\n";
287 :     }
288 :     $out;
289 :     }
290 : sh002i 1050
291 : gage 1066 sub dm_special_tops {
292 :     my %opts = @_;
293 :     my @top_labels = @{$opts{'top_labels'}};
294 :     my $ncols = scalar(@top_labels);
295 :     my $out = '';
296 :     my $j;
297 :     my ($brh, $erh) = ("",""); # Start and end raw html
298 :     if($main::displayMode eq 'Latex2HTML') {
299 :     $brh = "\\begin{rawhtml}";
300 :     $erh = "\\end{rawhtml}";
301 :     }
302 : jj 1097
303 : gage 1066 if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
304 :     for $j (@top_labels) {
305 :     $out .= '\smash{\raisebox{2.9ex}{\ensuremath{'.
306 :     $j . '}}} &';
307 :     }
308 :     chop($out); # remove last &
309 :     $out .= '\cr\noalign{\vskip -2.5ex}'."\n"; # want skip jump up 2.5ex
310 :     } elsif ($main::displayMode eq 'HTML' or $main::displayMode eq 'HTML_tth'
311 :     or $main::displayMode eq 'HTML_dpng'
312 :     or $main::displayMode eq 'HTML_img'
313 :     or $main::displayMode eq 'Latex2HTML') {
314 :     $out .= "$brh<tr><td>$erh"; # Skip a column for the left brace
315 :     for $j (@top_labels) {
316 :     $out .= "$brh<td>$erh". ' \('.$j.'\)'."$brh</td>$erh";
317 :     }
318 :     } else {
319 :     $out = "Error: dm_begin_matrix: Unknown displayMode: $main::displayMode.\n";
320 :     }
321 :     return $out;
322 :     }
323 :    
324 :     sub dm_mat_left {
325 :     my $numrows = shift;
326 :     my %opts = @_;
327 :     if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
328 :     return ""; # left delim is built into begin matrix
329 :     }
330 :     my $out='';
331 :     my $j;
332 :     my ($brh, $erh) = ("",""); # Start and end raw html
333 :     if($main::displayMode eq 'Latex2HTML') {
334 :     $brh = "\\begin{rawhtml}";
335 :     $erh = "\\end{rawhtml}";
336 :     }
337 :    
338 :     if($main::displayMode eq 'HTML_dpng'
339 :     or $main::displayMode eq 'HTML_img'
340 :     or $main::displayMode eq 'Latex2HTML') {
341 :     $out .= "$brh<tr valign=\"center\"><td nowrap=\"nowrap\" align=\"left\" rowspan=\"$numrows\">$erh";
342 :     $out .= dm_image_delimeter($numrows, $opts{'left'});
343 :     # $out .= "$brh<td><table border=0 cellspacing=5>\n$erh";
344 :     return $out;
345 :     }
346 :     # Mode is now tth
347 :    
348 :     $out .= "<tr valign=\"center\"><td nowrap=\"nowrap\" align=\"left\" rowspan=\"$numrows\">";
349 :     $out .= dm_tth_delimeter($numrows, $opts{'left'});
350 :     # $out .= "<td><table border=0 cellspacing=5>\n";
351 :     return $out;
352 :     }
353 :    
354 :     sub dm_mat_right {
355 :     my $numrows = shift;
356 :     my %opts = @_;
357 :     my $out='';
358 :     my $j;
359 :     my ($brh, $erh) = ("",""); # Start and end raw html
360 :     if($main::displayMode eq 'Latex2HTML') {
361 :     $brh = "\\begin{rawhtml}";
362 :     $erh = "\\end{rawhtml}";
363 :     }
364 :    
365 : jj 1097
366 : gage 1066 if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
367 :     return "";
368 :     }
369 :    
370 :     if($main::displayMode eq 'HTML_dpng'
371 :     or $main::displayMode eq 'Latex2HTML'
372 :     or $main::displayMode eq 'HTML_dpng') {
373 :     $out .= "$brh<td nowrap=\"nowrap\" align=\"right\" rowspan=\"$numrows\">$erh";
374 : jj 1097
375 : gage 1066 $out.= dm_image_delimeter($numrows, $opts{'right'});
376 :     return $out;
377 :     }
378 :    
379 :     # $out .= "</table>";
380 :     $out .= '<td nowrap="nowrap" align="left" rowspan="'.$numrows.'2">';
381 :     $out .= dm_tth_delimeter($numrows, $opts{'right'});
382 :     $out .= '</td>';
383 :     return $out;
384 :     }
385 :    
386 :     sub dm_end_matrix {
387 :     my %opts = @_;
388 : jj 1097
389 : gage 1066 my $out = "";
390 :     if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
391 :     $out .= "\\end{array}\\right$opts{right}";
392 :     $out .= $opts{'force_tex'} ? '' : "\\) ";
393 :     if($opts{'top_labels'}) {
394 :     $out .= '}} \dimen3=\ht3 \advance\dimen3 by 3ex \ht3=\dimen3'."\n".
395 :     '\box3\endgroup';
396 :     }
397 :     }
398 :     elsif ($main::displayMode eq 'Latex2HTML') {
399 :     $out .= "\n\\begin{rawhtml} </TABLE >\n\\end{rawhtml}";
400 :     }
401 :     elsif ($main::displayMode eq 'HTML' or $main::displayMode eq 'HTML_tth'
402 :     or $main::displayMode eq 'HTML_img'
403 :     or $main::displayMode eq 'HTML_dpng') {
404 :     $out .= "</TABLE>\n";
405 :     }
406 :     else {
407 :     $out = "Error: PGmatrixmacros: dm_end_matrix: Unknown displayMode: $main::displayMode.\n";
408 :     }
409 :     $out;
410 :     }
411 :    
412 :     # Make an image of a big delimiter for a matrix
413 :     sub dm_image_delimeter {
414 :     my $numRows = shift;
415 :     my $char = shift;
416 :     my ($out, $j);
417 :    
418 :     if($char eq ".") {return("");}
419 :     if($char eq "d") { # special treatment for dashed lines
420 :     $out='\(\vbox to '.($numRows*1.7).'\baselineskip ';
421 :     $out .='{\cleaders\hbox{\vbox{\hrule width0pt height3pt depth0pt';
422 :     $out .='\hrule width0.3pt height6pt depth0pt';
423 :     $out .='\hrule width0pt height3pt depth0pt}}\vfil}\)';
424 :     return($out);
425 :     }
426 :     if($char eq "|") {
427 :     $out='\(\vbox to '.($numRows*1.4).'\baselineskip ';
428 :     $out .='{\cleaders\vrule width0.3pt';
429 :     $out .='\vfil}\)';
430 :     return($out);
431 :     }
432 :     if($char eq "{") {$char = '\lbrace';}
433 :     if($char eq "}") {$char = '\rbrace';}
434 :     $out .= '\(\setlength{\arraycolsep}{0in}\left.\begin{array}{c}';
435 :     for($j=0;$j<=$numRows;$j++) { $out .= '\! \\\\'; }
436 :     $out .= '\end{array}\right'.$char.'\)';
437 :     return($out);
438 :     }
439 :    
440 :     # Basically uses a table of special characters and simple
441 :     # recipe to produce big delimeters a la tth mode
442 :     sub dm_tth_delimeter {
443 :     my $numRows = shift;
444 :     my $char = shift;
445 :    
446 :     if($char eq ".") { return("");}
447 :     my ($top, $mid, $bot, $extra);
448 :     my ($j, $out);
449 :    
450 :     if($char eq "(") { ($top, $mid, $bot, $extra) = ('æ','ç','è','ç');}
451 :     elsif($char eq ")") { ($top, $mid, $bot, $extra) = ('ö','÷','ø','÷');}
452 :     elsif($char eq "|") { ($top, $mid, $bot, $extra) = ('ê','ê','ê','ê');}
453 :     elsif($char eq "[") { ($top, $mid, $bot, $extra) = ('é','ê','ë','ê');}
454 :     elsif($char eq "]") { ($top, $mid, $bot, $extra) = ('ù','ú','û','ú');}
455 :     elsif($char eq "{") { ($top, $mid, $bot, $extra) = ('ì','ï','î','í');}
456 :     elsif($char eq "}") { ($top, $mid, $bot, $extra) = ('ü','ï','þ','ý');}
457 :     else { warn "Unknown delimiter in dm_tth_delimeter";}
458 :    
459 :     # old version
460 :     # $out = '<td nowrap="nowrap" align="left"><font face="symbol">';
461 :     $out = '<font face="symbol">';
462 :     $out .= "$top<br />";
463 :     for($j=1;$j<$numRows; $j++) {
464 :     $out .= "$mid<br />";
465 :     }
466 :     $out .= "$extra<br />";
467 :     for($j=1;$j<$numRows; $j++) {
468 :     $out .= "$mid<br />";
469 :     }
470 :     $out .= "$bot</font></td>";
471 :     return $out;
472 :     }
473 :    
474 :     # Make a row for the matrix
475 :     sub dm_mat_row {
476 :     my $elements = shift;
477 :     my $tmp = shift;
478 :     my @align = @{$tmp} ;
479 :     my %opts = @_;
480 :    
481 :     if($elements eq 'hline') {
482 :     if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
483 :     return '\hline ';
484 :     } else {
485 :     # Making a hline in a table
486 :     return '<tr><td colspan="'.scalar(@align).'"><hr></td></tr>';
487 :     }
488 :     }
489 : jj 1097
490 : gage 1066 my @elements = @{$elements};
491 :     my $out = "";
492 :     my ($brh, $erh) = ("",""); # Start and end raw html
493 :     my $element;
494 :     if($main::displayMode eq 'Latex2HTML') {
495 :     $brh = "\\begin{rawhtml}";
496 :     $erh = "\\end{rawhtml}";
497 :     }
498 :     if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
499 :     while (@elements) {
500 :     $element= shift(@elements);
501 :     if(ref($element) eq 'Fraction') {
502 :     $element= $element->print_inline();
503 :     }
504 :     $out .= "$element &";
505 :     }
506 :     chop($out); # remove last &
507 :     $out .= "\\cr \n";
508 :     # carriage returns must be added manually for tex
509 :     } elsif ($main::displayMode eq 'HTML' or $main::displayMode eq 'HTML_tth'
510 :     or $main::displayMode eq 'HTML_dpng'
511 :     or $main::displayMode eq 'HTML_img'
512 :     or $main::displayMode eq 'Latex2HTML') {
513 :     if(not $opts{'isfirst'}) { $out .= "$brh\n<TR>\n$erh";}
514 :     while (@elements) {
515 :     my $myalign;
516 :     $myalign = shift @align;
517 :     if($myalign eq "|" or $myalign eq "d") {
518 :     if($opts{'isfirst'} && $main::displayMode ne 'HTML_tth') {
519 :     $out .= $brh.'<td rowspan="'.$opts{'isfirst'}.'">'.$erh;
520 :     $out .= dm_image_delimeter($opts{'isfirst'}-1, $myalign);
521 :     } elsif($main::displayMode eq 'HTML_tth') {
522 :     if($myalign eq "d") { # dashed line in tth mode
523 :     $out .= '<td> | </td>';
524 :     } elsif($opts{'isfirst'}) { # solid line in tth mode
525 :     $out .= '<td rowspan="'.$opts{'isfirst'}.'"<table border="0"><tr>';
526 :     $out .= dm_tth_delimeter($opts{'isfirst'}-1, "|");
527 :     $out .= '</td></tr></table>';
528 :     }
529 :     }
530 :     } else {
531 :     if($myalign eq "c") { $myalign = "center";}
532 :     if($myalign eq "l") { $myalign = "left";}
533 :     if($myalign eq "r") { $myalign = "right";}
534 :     $element= shift(@elements);
535 :     if (ref($element) eq 'Fraction') {
536 :     $element= $element->print_inline();
537 :     }
538 :     $out .= "$brh<TD nowrap=\"nowrap\" align=\"$myalign\">$erh" .
539 :     $element . "$brh</TD>$erh";
540 :     }
541 :     }
542 :     if(not $opts{'isfirst'}) {$out .="$brh</TR>$erh\n";}
543 :     }
544 :     else {
545 :     $out = "Error: dm_mat_row: Unknown displayMode: $main::displayMode.\n";
546 :     }
547 :     $out;
548 :     }
549 :    
550 :     =head4 mbox
551 :    
552 :     Usage \{ mbox(thing1, thing2, thing3) \}
553 :     \{ mbox([thing1, thing2, thing3], valign=>'top') \}
554 :    
555 :     mbox takes a list of constructs, such as strings, or outputs of
556 :     display_matrix, and puts them together on a line. Without mbox, the
557 :     output of display_matrix would always start a new line.
558 :    
559 :     The inputs can be just listed, or given as a reference to an array.
560 :     With the latter, optional arguments can be given.
561 :    
562 :     Optional arguments are allowbreaks=>'yes' to allow line breaks in TeX
563 :     output; and valign which sets vertical alignment on web page output.
564 :    
565 :     =cut
566 : jj 1097
567 : gage 1066 sub mbox {
568 :     my $inList = shift;
569 :     my %opts;
570 :     if(ref($inList) eq 'ARRAY') {
571 :     %opts = @_;
572 :     } else {
573 :     %opts = ();
574 :     $inList = [$inList, @_];
575 :     }
576 :    
577 :     set_default_options(\%opts,
578 :     '_filter_name' => 'mbox',
579 :     'valign' => 'middle',
580 :     'allowbreaks' => 'no',
581 :     'allow_unknown_options'=> 0);
582 :     if(! $opts{'allowbreaks'}) { $opts{'allowbreaks'}='no';}
583 :     my $out = "";
584 :     my $j;
585 :     my ($brh, $erh) = ("",""); # Start and end raw html if needed
586 :     if($main::displayMode eq 'Latex2HTML') {
587 :     $brh = "\\begin{rawhtml}";
588 :     $erh = "\\end{rawhtml}";
589 :     }
590 :     my @hlist = @{$inList};
591 :     if($main::displayMode eq 'TeX') {
592 :     if($opts{allowbreaks} ne 'no') {$out .= '\mbox{';}
593 :     for $j (@hlist) { $out .= $j;}
594 :     if($opts{allowbreaks} ne 'no') {$out .= '}';}
595 :     } else {
596 :     $out .= qq!$brh<table><tr valign="$opts{'valign'}">$erh!;
597 :     for $j (@hlist) {
598 :     $out .= qq!$brh<td align="center" nowrap="nowrap">$erh$j$brh</td>$erh!;
599 :     }
600 :     $out .= "$brh</table>$erh";
601 :     }
602 :     return $out;
603 :     }
604 : jj 1097
605 : gage 1066
606 : sh002i 1050 =head4 ra_flatten_matrix
607 :    
608 :     Usage: ra_flatten_matrix($A)
609 : jj 1097
610 : sh002i 1050 where $A is a matrix object
611 :     The output is a reference to an array. The matrix is placed in the array by iterating
612 :     over columns on the inside
613 :     loop, then over the rows. (e.g right to left and then down, as one reads text)
614 :    
615 :    
616 :     =cut
617 :    
618 :    
619 :     sub ra_flatten_matrix{
620 :     my $matrix = shift;
621 :     warn "The argument must be a matrix object" unless ref($matrix) =~ /Matrix/;
622 :     my @array = ();
623 :     my ($rows, $cols ) = $matrix->dim();
624 :     foreach my $i (1..$rows) {
625 :     foreach my $j (1..$cols) {
626 :     push(@array, $matrix->element($i,$j) );
627 :     }
628 :     }
629 :     \@array;
630 :     }
631 :    
632 :     # This subroutine is probably obsolete and not generally useful. It was patterned after the APL
633 : jj 1097 # constructs for multiplying matrices. It might come in handy for non-standard multiplication of
634 : sh002i 1050 # of matrices (e.g. mod 2) for indice matrices.
635 :     sub apl_matrix_mult{
636 :     my $ra_a= shift;
637 :     my $ra_b= shift;
638 :     my %options = @_;
639 :     my $rf_op_times= sub {$_[0] *$_[1]};
640 :     my $rf_op_plus = sub {my $sum = 0; my @in = @_; while(@in){ $sum = $sum + shift(@in) } $sum; };
641 :     $rf_op_times = $options{'times'} if defined($options{'times'}) and ref($options{'times'}) eq 'CODE';
642 :     $rf_op_plus = $options{'plus'} if defined($options{'plus'}) and ref($options{'plus'}) eq 'CODE';
643 :     my $rows = @$ra_a;
644 :     my $cols = @{$ra_b->[0]};
645 :     my $k_size = @$ra_b;
646 :     my $out ;
647 :     my ($i, $j, $k);
648 :     for($i=0;$i<$rows;$i++) {
649 :     for($j=0;$j<$cols;$j++) {
650 :     my @r = ();
651 :     for($k=0;$k<$k_size;$k++) {
652 :     $r[$k] = &$rf_op_times($ra_a->[$i]->[$k] , $ra_b->[$k]->[$j]);
653 :     }
654 :     $out->[$i]->[$j] = &$rf_op_plus( @r );
655 :     }
656 :     }
657 :     $out;
658 :     }
659 :    
660 :     sub matrix_mult {
661 :     apl_matrix_mult($_[0], $_[1]);
662 :     }
663 :    
664 :     sub make_matrix{
665 :     my $function = shift;
666 :     my $rows = shift;
667 :     my $cols = shift;
668 :     my ($i, $j, $k);
669 :     my $ra_out;
670 :     for($i=0;$i<$rows;$i++) {
671 :     for($j=0;$j<$cols;$j++) {
672 :     $ra_out->[$i]->[$j] = &$function($i,$j);
673 :     }
674 :     }
675 :     $ra_out;
676 :     }
677 :    
678 : gage 1066
679 :     =head5 answer_matrix
680 :    
681 :     Usage \[ \{ answer_matrix(rows,columns,width_of_ans_rule, @options) \} \]
682 : jj 1097
683 : gage 1066 Creates an array of answer blanks and passes it to display_matrix which returns
684 :     text which represents the matrix in TeX format used in math display mode. Answers
685 :     are then passed back to whatever answer evaluators you write at the end of the problem.
686 :     (note, if you have an m x n matrix, you will need mn answer evaluators, and they will be
687 : jj 1097 returned to the evaluaters starting in the top left hand corner and proceed to the left
688 : gage 1066 and then at the end moving down one row, just as you would read them.)
689 : jj 1097
690 : gage 1066 The options are passed on to display_matrix.
691 :    
692 :    
693 :     =cut
694 :    
695 :    
696 :     sub answer_matrix{
697 :     my $m = shift;
698 :     my $n = shift;
699 :     my $width = shift;
700 :     my @options = @_;
701 :     my @array=();
702 :     for( my $i = 0; $i < $m; $i+=1)
703 :     {
704 :     my @row_array = ();
705 : jj 1097
706 : gage 1066 for( my $i = 0; $i < $n; $i+=1)
707 :     {
708 :     push @row_array, ans_rule($width);
709 : jj 1097 }
710 : gage 1066 my $r_row_array = \@row_array;
711 :     push @array, $r_row_array;
712 :     }
713 :     display_matrix( \@array, @options );
714 : jj 1097
715 : gage 1066 }
716 : jj 1097
717 : sh002i 1050 # sub format_answer{
718 :     # my $ra_eigenvalues = shift;
719 :     # my $ra_eigenvectors = shift;
720 :     # my $functionName = shift;
721 :     # my @eigenvalues=@$ra_eigenvalues;
722 :     # my $size= @eigenvalues;
723 :     # my $ra_eigen = make_matrix( sub {my ($i,$j) = @_; ($i==$j) ? "e^{$eigenvalues[$j] t}": 0 }, $size,$size);
724 :     # my $out = qq!
725 :     # $functionName(t) =! .
726 :     # displayMatrix(apl_matrix_mult($ra_eigenvectors,$ra_eigen,
727 :     # 'times'=>sub{($_[0] and $_[1]) ? "$_[0]$_[1]" : ''},
728 :     # 'plus'=>sub{ my $out = join("",@_); ($out) ?$out : '0' }
729 :     # ) ) ;
730 :     # $out;
731 :     # }
732 :     # sub format_vector_answer{
733 :     # my $ra_eigenvalues = shift;
734 :     # my $ra_eigenvectors = shift;
735 :     # my $functionName = shift;
736 :     # my @eigenvalues=@$ra_eigenvalues;
737 :     # my $size= @eigenvalues;
738 :     # my $ra_eigen = make_matrix( sub {my ($i,$j) = @_; ($i==$j) ? "e^{$eigenvalues[$j] t}": 0 }, $size,$size);
739 :     # my $out = qq!
740 :     # $functionName(t) =! .
741 :     # displayMatrix($ra_eigenvectors)."e^{$eigenvalues[0] t}" ;
742 :     # $out;
743 :     # }
744 :     # sub format_question{
745 :     # my $ra_matrix = shift;
746 :     # my $out = qq! y'(t) = ! . displayMatrix($B). q! y(t)!
747 : jj 1097 #
748 : sh002i 1050 # }
749 :    
750 :     1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9