[system] / trunk / webwork / system / courseScripts / PGmatrixmacros.pl Repository:
ViewVC logotype

View of /trunk/webwork/system/courseScripts/PGmatrixmacros.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 826 - (download) (as text) (annotate)
Tue May 13 16:12:41 2003 UTC (10 years ago) by jj
File size: 13854 byte(s)
Changed display_matrix to display_matrix_mm, added display_matrix_math_mode, and changed displaymat to display_matrix.

    1 #!/usr/local/bin/webwork-perl
    2 
    3 ###########
    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 Many of the other macros work with vectors and matrices stored as anonymous arrays.
   18 
   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 # more work -- particularly for checking relative tolerance.  More work needs to be done if this is
   34 # 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   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                          # 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 
   73 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 
   79     my $ans_hash = new AnswerHash;
   80     my @in = split("\0",$in);
   81     my @correct_vector=@$correct_vector;
   82     $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 
   87     my $correct_length = vec_dot($correct_vector,$correct_vector);
   88     my $in_length = vec_dot(\@in,\@in);
   89     return($ans_hash) if $in_length == 0;
   90 
   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 
   99     } else {
  100       $ans_hash->{score} = 1 if vec_dot(\@in,\@in) == 0;
  101     }
  102     $ans_hash;
  103 
  104     };
  105 
  106     $ans_eval;
  107 }
  108 
  109 ############
  110 
  111 =head4  display_matrix
  112 
  113     Usage   \[ \{   display_matrix($A)  \} \]
  114              \[ \{ display_matrix([ [ 1, 3], [4, 6] ])  \} \]
  115 
  116     Output is text which represents the matrix in TeX format used in math display mode.
  117 
  118 
  119 =cut
  120 
  121 
  122 sub display_matrix_mm{    # will display a matrix in tex format.
  123                        # the matrix can be either of type array or type 'Matrix'
  124 #   my $ra_matrix = shift;
  125 #   my $out='';
  126 #   if (ref($ra_matrix) eq 'Matrix' )  {
  127 #     my ($rows, $cols) = $ra_matrix->dim();
  128 #     $out = q!\\left(\\begin{array}{! . 'c'x$cols . q!}!;
  129 #     for( my $i=1; $i<=$rows; $i++) {
  130 #         for (my $j=1; $j<=$cols; $j++) {
  131 #           my $entry = $ra_matrix->element($i,$j);
  132 #           $entry = "#" unless defined($entry);
  133 #           $out.= $entry;
  134 #           $out .= ($j < $cols) ? ' & ' : "\\cr\n";
  135 #         }
  136 #     }
  137 #     $out .= "\\end{array}\\right)";
  138 #   } elsif( ref($ra_matrix) eq 'ARRAY') {
  139 #     my $rows = @$ra_matrix;
  140 #     my $cols = @{$ra_matrix->[0]};
  141 #     $out = q!\\left(\\begin{array}{! . 'c' x$cols . q!}!;
  142 #     for(my $i=0; $i<$rows; $i++) {
  143 #         my @row = @{$ra_matrix->[$i]};
  144 #         while (@row) {
  145 #           my $entry = shift(@row);
  146 #           $entry = "#" unless defined($entry);
  147 #           $out.= $entry;
  148 #           if (@row) {
  149 #             $out .= "& ";
  150 #           } else {
  151 #             next;
  152 #           }
  153 #         }
  154 #       $out .=  "\\cr\n";
  155 #     }
  156 #       $out .= "\\end{array}\\right)";
  157 #   } else {
  158 #     warn "The input" . ref($ra_matrix) . " doesn't make sense as input to display_matrix. ";
  159 #   }
  160 #   $out;
  161 
  162   return display_matrix(@_, 'force_tex'=>1);
  163 }
  164 
  165 sub display_matrix_math_mode {
  166   return display_matrix_mm(@_);
  167 }
  168 
  169 sub display_matrix {
  170   my $ra_matrix = shift;
  171   my %opts = @_;
  172   set_default_options(\%opts,
  173                       '_filter_name' => 'displaymat',
  174                       'force_tex' => 0,
  175                       'allow_unknown_options'=> 1);
  176 
  177   my ($numRows, $numCols, @myRows);
  178 
  179   if (ref($ra_matrix) eq 'Matrix' )  {
  180     ($numRows, $numCols) = $ra_matrix->dim();
  181     for( my $i=0; $i<$numRows; $i++) {
  182       $myRows[$i] = [];
  183       for (my $j=0; $j<$numCols; $j++) {
  184         my $entry = $ra_matrix->element($i+1,$j+1);
  185         $entry = "#" unless defined($entry);
  186         push @{ $myRows[$i] },  $entry;
  187       }
  188     }
  189   } else { # matrix is input at [ [1,2,3],[4,5,6]]
  190     @myRows = @{$ra_matrix};
  191     $numRows = scalar(@myRows);
  192     my @arow = @{$myRows[0]};
  193     $numCols= scalar(@arow);   #number of columns in table
  194   }
  195   my $out;
  196   my $j;
  197   my $alignString=''; # alignment as a string for dvi/pdf
  198   my $alignList;     # alignment as a list
  199 
  200   if(defined($opts{'align'})) {
  201     $alignString= $opts{'align'};
  202     $alignString =~ tr/s/|/; # Treat "s" as "|"
  203     @$alignList = split //, $opts{'align'};
  204   } else {
  205     for($j=0; $j<$numCols; $j++) {
  206       $alignList->[$j] = "c";
  207       $alignString .= "c";
  208     }
  209   }
  210 
  211   $out .= dm_begin_matrix($alignString, %opts);
  212   $out .= dm_mat_left($numRows, %opts);
  213   for $j (@myRows) {
  214     $out .= dm_mat_row($j, $alignList, %opts);
  215   }
  216   $out .= dm_mat_right($numRows, %opts);
  217   $out .= dm_end_matrix(%opts);
  218   $out;
  219 }
  220 
  221 sub dm_begin_matrix {
  222   my ($aligns)=shift;   #alignments of columns in table
  223   my %opts = @_;
  224   my $out = "";
  225   if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
  226     $out .= "\n";
  227     $out .= $opts{'force_tex'} ? '' : '\(';
  228     $out .= "\\displaystyle\\left(\\begin{array}{$aligns} \n";
  229     }
  230   elsif ($main::displayMode eq 'Latex2HTML') {
  231     $out .= "\n\\begin{rawhtml} <TABLE  BORDER=0>\n\\end{rawhtml}";
  232     }
  233   elsif ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth' || $main::displayMode eq 'HTML_dpng') {
  234     $out .= "<TABLE BORDER=0>\n"
  235   }
  236   else {
  237     $out = "Error: dm_begin_matrix: Unknown displayMode: $main::displayMode.\n";
  238     }
  239   $out;
  240 }
  241 
  242 
  243 sub dm_mat_left {
  244   my $numrows = shift;
  245   my %opts = @_;
  246   if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
  247     return "";
  248   }
  249   my $out='';
  250   my $j;
  251 
  252   if(($main::displayMode eq 'HTML_dpng') || ($main::displayMode eq 'Latex2HTML')) {
  253 #     if($numrows>12) {   $numrows = 12; }
  254     if($main::displayMode eq 'Latex2HTML') { $out .= '\begin{rawhtml}'; }
  255     $out .= "<tr><td nowrap=\"nowrap\" align=\"left\">";
  256     if($main::displayMode eq 'Latex2HTML') { $out .= '\end{rawhtml}'; }
  257 #     $out .= "<img alt=\"(\" src = \"".
  258 #       $main::imagesURL."/left$numrows.png\" >";
  259 #     return $out;
  260     $out .= '\(\left.\begin{array}{c}';
  261     for($j=0;$j<$numrows;$j++)  { $out .= ' \\\\'; }
  262     $out .= '\end{array}\right(\)';
  263 
  264     if($main::displayMode eq 'Latex2HTML') { $out .= '\begin{rawhtml}'; }
  265     $out .= "<td><table border=0  cellspacing=5>\n";
  266     if($main::displayMode eq 'Latex2HTML') { $out .= '\end{rawhtml}'; }
  267     return $out;
  268   }
  269   # Mode is now tth
  270   $out = "<tr><td nowrap=\"nowrap\" align=\"left\"><font face=\"symbol\">æ<br />";
  271   for($j=0;$j<$numrows;$j++)  {
  272     $out .= "ç<br />";
  273   }
  274   $out .= "è</font></td>\n";
  275   $out .= "<td><table border=0  cellspacing=5>\n";
  276   return $out;
  277 }
  278 
  279 sub dm_mat_right {
  280   my $numrows = shift;
  281   my %opts = @_;
  282   my $out='';
  283   my $j;
  284 
  285   if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
  286     return "";
  287   }
  288 
  289   if(($main::displayMode eq 'HTML_dpng') || ($main::displayMode eq 'Latex2HTML')) {
  290     if($main::displayMode eq 'Latex2HTML') { $out .= '\begin{rawhtml}'; }
  291     $out .= "</table><td nowrap=\"nowrap\" align=\"right\">";
  292     if($main::displayMode eq 'Latex2HTML') { $out .= '\end{rawhtml}'; }
  293 
  294 #   $out .= "<img alt=\"(\" src = \"".
  295 #     "/webwork_system_html/images"."/right$numrows.png\" >";
  296     $out .= '\(\left)\begin{array}{c}';
  297     for($j=0;$j<$numrows;$j++)  { $out .= ' \\\\'; }
  298     $out .= '\end{array}\right.\)';
  299     return $out;
  300   }
  301 
  302   $out .= "</table>";
  303   $out .= "<td nowrap=\"nowrap\" align=\"left\"><font face=\"symbol\">ö<br />";
  304   for($j=0;$j<$numrows;$j++)  {
  305     $out .= "÷<br />";
  306   }
  307   $out .= "ø</font></td>\n";
  308   return $out;
  309 }
  310 
  311 sub dm_end_matrix {
  312   my %opts = @_;
  313 
  314   my $out = "";
  315   if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
  316     $out .= "\n\\end{array}\\right)";
  317     $out .= $opts{'force_tex'} ? '' : "\\)\n";
  318     }
  319   elsif ($main::displayMode eq 'Latex2HTML') {
  320     $out .= "\n\\begin{rawhtml} </TABLE >\n\\end{rawhtml}";
  321     }
  322   elsif ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth' || $main::displayMode eq 'HTML_dpng') {
  323     $out .= "</TABLE>\n";
  324     }
  325   else {
  326     $out = "Error: PGmatrixmacros: dm_end_matrix: Unknown displayMode: $main::displayMode.\n";
  327     }
  328   $out;
  329 }
  330 
  331 
  332 sub dm_mat_row {
  333   my $elements = shift;
  334   my $tmp = shift;
  335   my @align =  @{$tmp} ;
  336   my %opts = @_;
  337   my @elements = @{$elements};
  338   my $out = "";
  339   if ($main::displayMode eq 'TeX' or $opts{'force_tex'}) {
  340     while (@elements) {
  341       $out .= shift(@elements) . " &";
  342       }
  343      chop($out); # remove last &
  344      $out .= "\\cr  \n";
  345      # carriage returns must be added manually for tex
  346     }
  347   elsif ($main::displayMode eq 'Latex2HTML') {
  348     $out .= "\n\\begin{rawhtml}\n<TR>\n\\end{rawhtml}\n";
  349     while (@elements) {
  350       $out .= " \n\\begin{rawhtml}\n<TD> \n\\end{rawhtml}\n" . shift(@elements) . " \n\\begin{rawhtml}\n</TD> \n\\end{rawhtml}\n";
  351       }
  352     $out .= " \n\\begin{rawhtml}\n</TR> \n\\end{rawhtml}\n";
  353   }
  354   elsif ($main::displayMode eq 'HTML' || $main::displayMode eq 'HTML_tth' || $main::displayMode eq 'HTML_dpng') {
  355     $out .= "<TR><td nowrap=\"nowrap\">\n";
  356     while (@elements) {
  357       my $myalign;
  358       #do {$myalign = shift @align;} until($myalign ne "|");
  359       $myalign = shift @align;
  360       if($myalign eq "|") {
  361         $out .= '<td> | </td>';
  362       } else {
  363         if($myalign eq "c") { $myalign = "center";}
  364         if($myalign eq "l") { $myalign = "left";}
  365         if($myalign eq "r") { $myalign = "right";}
  366         $out .= "<TD nowrap=\"nowrap\" align=\"$myalign\">" . shift(@elements) . "</TD>";
  367       }
  368       }
  369     $out .= "<td>\n</TR>\n";
  370   }
  371   else {
  372     $out = "Error: dm_mat_row: Unknown displayMode: $main::displayMode.\n";
  373     }
  374   $out;
  375 }
  376 
  377 
  378 
  379 =head4   ra_flatten_matrix
  380 
  381     Usage:   ra_flatten_matrix($A)
  382 
  383       where $A is a matrix object
  384       The output is a reference to an array.  The matrix is placed in the array by iterating
  385       over  columns on the inside
  386       loop, then over the rows. (e.g right to left and then down, as one reads text)
  387 
  388 
  389 =cut
  390 
  391 
  392 sub ra_flatten_matrix{
  393   my $matrix = shift;
  394   warn "The argument must be a matrix object" unless ref($matrix) =~ /Matrix/;
  395   my @array = ();
  396   my ($rows, $cols ) = $matrix->dim();
  397   foreach my $i (1..$rows) {
  398     foreach my $j (1..$cols) {
  399         push(@array, $matrix->element($i,$j)  );
  400       }
  401     }
  402     \@array;
  403 }
  404 
  405 # This subroutine is probably obsolete and not generally useful.  It was patterned after the APL
  406 # constructs for multiplying matrices. It might come in handy for non-standard multiplication of
  407 # of matrices (e.g. mod 2) for indice matrices.
  408 sub apl_matrix_mult{
  409   my $ra_a= shift;
  410   my $ra_b= shift;
  411   my %options = @_;
  412   my $rf_op_times= sub {$_[0] *$_[1]};
  413   my $rf_op_plus = sub {my $sum = 0; my @in = @_; while(@in){ $sum = $sum + shift(@in) } $sum; };
  414   $rf_op_times = $options{'times'} if defined($options{'times'}) and ref($options{'times'}) eq 'CODE';
  415   $rf_op_plus = $options{'plus'} if defined($options{'plus'}) and ref($options{'plus'}) eq 'CODE';
  416   my $rows = @$ra_a;
  417   my $cols = @{$ra_b->[0]};
  418   my $k_size = @$ra_b;
  419   my $out ;
  420   my ($i, $j, $k);
  421   for($i=0;$i<$rows;$i++) {
  422     for($j=0;$j<$cols;$j++) {
  423         my @r = ();
  424         for($k=0;$k<$k_size;$k++) {
  425           $r[$k] =  &$rf_op_times($ra_a->[$i]->[$k] , $ra_b->[$k]->[$j]);
  426         }
  427       $out->[$i]->[$j] = &$rf_op_plus( @r );
  428     }
  429   }
  430   $out;
  431 }
  432 
  433 sub matrix_mult {
  434   apl_matrix_mult($_[0], $_[1]);
  435 }
  436 
  437 sub make_matrix{
  438   my $function = shift;
  439   my $rows = shift;
  440   my $cols = shift;
  441   my ($i, $j, $k);
  442   my $ra_out;
  443   for($i=0;$i<$rows;$i++) {
  444     for($j=0;$j<$cols;$j++) {
  445       $ra_out->[$i]->[$j] = &$function($i,$j);
  446     }
  447   }
  448   $ra_out;
  449 }
  450 
  451 
  452 # sub format_answer{
  453 #   my $ra_eigenvalues = shift;
  454 #   my $ra_eigenvectors = shift;
  455 #   my $functionName = shift;
  456 #   my @eigenvalues=@$ra_eigenvalues;
  457 #   my $size= @eigenvalues;
  458 #   my $ra_eigen = make_matrix( sub {my ($i,$j) = @_; ($i==$j) ? "e^{$eigenvalues[$j] t}": 0 }, $size,$size);
  459 #   my $out = qq!
  460 #         $functionName(t) =! .
  461 #                             displayMatrix(apl_matrix_mult($ra_eigenvectors,$ra_eigen,
  462 #                                     'times'=>sub{($_[0] and $_[1]) ? "$_[0]$_[1]"  : ''},
  463 #                                     'plus'=>sub{ my $out = join("",@_); ($out) ?$out : '0' }
  464 #                                     ) ) ;
  465 #        $out;
  466 # }
  467 # sub format_vector_answer{
  468 #   my $ra_eigenvalues = shift;
  469 #   my $ra_eigenvectors = shift;
  470 #   my $functionName = shift;
  471 #   my @eigenvalues=@$ra_eigenvalues;
  472 #   my $size= @eigenvalues;
  473 #   my $ra_eigen = make_matrix( sub {my ($i,$j) = @_; ($i==$j) ? "e^{$eigenvalues[$j] t}": 0 }, $size,$size);
  474 #   my $out = qq!
  475 #         $functionName(t) =! .
  476 #                             displayMatrix($ra_eigenvectors)."e^{$eigenvalues[0] t}" ;
  477 #        $out;
  478 # }
  479 # sub format_question{
  480 #   my $ra_matrix = shift;
  481 #   my $out = qq! y'(t) = ! . displayMatrix($B). q! y(t)!
  482 #
  483 # }
  484 
  485 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9