#!/usr/bin/perl ############################################################################## # # # compare.cgi - Compares matrix exponential and symbolic methods of solving # # a differential equation. # # # # Revision: 1.0 1/20/98 # # # # Author: David Harris # # # # History: None yet. # # # # # # COPYRIGHT (C) 1998 David R. Harris All Rights Reserved. # # # ############################################################################## require matrix; require formparse; require weberror; ############################################################################## # DOCUMENTATION # # This will be a web based program which will allow the user to explore the # accuracy of solving differential equations via matrix exponential. The # user will enter a differential equation, initial conditions, and a symbolic # solution. They then enter what kind of tests they want to do, and a nice # output is generated. # # This program will generate the form when it is retrieved via the HTTP GET # method. ############################################################################## # SUB: print_page sub print_page { # # Print the header n stuff # print <<"EOT"; DiffEq Matrix Exponentiation Explorer

DiffEq Matrix Exponentiation Explorer

This program allows the user to numerically solve linear homogeneous differential equations using matrix exponentiation. The user can also enter the symbolic solution and compare with the numerically derived solutions.

So, sit back, relax, and enjoy the show. Err.. fill out the form below. Or, scroll down after the form and work from a pre-created example.


Form

EOT print <<'EOT';   List of the coefficents.
  Inital point ( t0 ).
  List of the inital conitions.
Symbolic solution.
  Value to explore ( t ).
Order of matrix exponental to explore.
  From this value
  To this value
  By steps of this value

How may steps to take.
  From this value
  To this value
  By steps of this value

  


Examples

These are pre-prepared examples. When you click the "load it" button the values for the example will be loaded into the form above. You can then submit the values as they are, or modify them if you wish. Then click the submit button to generate the output.

Example One

Example Two

EOT exit(0); } ############################################################################## # SUB: print_response_header sub print_response_header { # # Print the header n stuff # print <<"EOT"; DiffEq Matrix Exponentiation Explorer

DiffEq Matrix Exponentiation Explorer

Here is the output your request request generates.

Your request

Coefficients    $form->{coefficients}
Initial t value    $form->{init_t}
Inital values    $form->{init_values}
Symbolic solution   $form->{sym_solution}
t value    $form->{t_value}
Orders to look    From $form->{order_from} to $form->{order_to} by steps of $form->{order_step}
Steps to look    From $form->{steps_from} to $form->{steps_to} by steps of $form->{steps_step}

EOT } ############################################################################## # SUB: my_die sub my_die { weberror::error(@_); weberror::debug_report($form_obj, $debug_string); exit(1); } ############################################################################## ############################################################################## # MAIN MAIN: { print "Content-type: text/html\n\n"; if ( 0 && !defined $ENV{'REQUEST_METHOD'} ) { $form = { coefficients => '1, -1, -6', init_t => '0', init_values => '1, 0', order_from => '15', order_to => '10', order_step => '', steps_from => '10', steps_to => '8', steps_step => '', sym_solution => '0.4 * exp( 3.0 * $t ) + 0.6 * exp( -2.0 * $t )', t_value => '1', }; } else { # # Print out the request page, if they need it # print_page if ( $ENV{'REQUEST_METHOD'} eq 'GET' ); # # Parse the form values # $form_obj = formparse->new('POST'); $form = $form_obj->get_single_info_hash_ref; $form_obj->require( [qw{ steps_to steps_step order_to order_step }], [qw{ coefficients init_t init_values sym_solution order_from steps_from t_value}], "[You did not fill in a required form value]" ); } $form->{coefficients} =~ s/^[^-1-90.]+//; @coefficients = split(/[^-1-90.]+/, $form->{coefficients}); $form->{init_values} =~ s/^[^-1-90.]+//; @init_values = split(/[^-1-90.]+/, $form->{init_values}); $init_t = $form->{init_t}; $t_value = $form->{t_value}; $sym_solution = $form->{sym_solution}; $sym_solution_sub = eval(" sub { my \$t = \@_[0]; return $sym_solution } "); main::my_die("Invalid symbolic solution. Error = $@") if ( $@ ne '' ); main::my_die("The number of coefficents and initial values must match") if ( $#coefficients != $#init_values + 1 ); $form->{order_to} = $form->{order_from} if ( '' eq $form->{order_to} ); $form->{order_step} = 1 if ( '' eq $form->{order_step} ); $form->{steps_to} = $form->{steps_from} if ( '' eq $form->{steps_to} ); $form->{steps_step} = 1 if ( '' eq $form->{steps_step} ); ($form->{order_from}, $form->{order_to}) = ($form->{order_to}, $form->{order_from}) if ( $form->{order_from} > $form->{order_to} ); ($form->{steps_from}, $form->{steps_to}) = ($form->{steps_to}, $form->{steps_from}) if ( $form->{steps_from} > $form->{steps_to} ); $form->{order_to} = int $form->{order_to}; $form->{order_from} = int $form->{order_from}; $form->{order_step} = int $form->{order_step}; $form->{steps_to} = int $form->{steps_to}; $form->{steps_from} = int $form->{steps_from}; $form->{steps_step} = int $form->{steps_step}; # # Do the precomputation for the matrix exponential # # NOTE: Currently limited to third order diff equations foreach $this_coeff ( @coefficients ) { push(@top_row, -1.0 * $this_coeff / @coefficients[0]); } @top_row = reverse(@top_row); pop(@top_row); @top_row = reverse(@top_row); @additional_rows = (); foreach $shift ( 0 .. ($#top_row - 1) ) { my @this_row = (0) x ( $#top_row + 1 ); $this_row[$shift] = 1; push(@additional_rows, [ @this_row ]); } $m = matrix::new([ [ @top_row ], @additional_rows ]); $init_values = { width => 0, height => $#init_values, data => [ reverse @init_values ], }; $precompute = matrix::matrix_exponential_do_precompute($m, $form->{order_to}); # # Print out the response header # print_response_header(); print <<"EOT";


Detailed results

EOT # # Loop through the step size # for ( $steps = $form->{steps_from} ; $steps <= $form->{steps_to} ; $steps += $form->{steps_step} ) { next if ( $steps == 0 ); $step = ( 0.0 + $t_value - $init_t ) / $steps; # # Generate the matrix exponential # $exponentials = matrix::matrix_exponential_use_precompute($precompute, $step, $form->{order_to}); for ( $order = $form->{order_from} ; $order <= $form->{order_to} ; $order += $form->{order_step} ) { # # Print the html header # print <<"EOT"; EOT # # Loop through multiplying to get the answer # $max_error = 0; $this_exponential = $exponentials->{$order}; $t_matrix = $init_values; for ( $this_step = 1 ; $this_step <= $steps ; $this_step++ ) { $t = $init_t + $step * $this_step; $t_matrix = matrix::multiply($this_exponential, $t_matrix); $numeric_y = $t_matrix->{data}[ $#{$t_matrix->{data}} ]; $symbolic_y = &$sym_solution_sub($t); $error = abs( $numeric_y - $symbolic_y ); $max_error = $error if ( $error > $max_error ); print <<"EOT"; EOT } # # Print out the result # print <<"EOT"; EOT # # Store the result for the summary table # $summary_table->{$steps}{$order} = $error; } } # # Print the detailed results footer # print <<"EOT";
---  steps = $steps, order = $order
 
t numeric value symbolic value error
$t $numeric_y $symbolic_y $error
 
steps      = $steps
step size  = $step
order      = $order
 
max error  = $max_error
error at t = $error
 

EOT # # Print the summary header # print <<"EOT";


Summary of results

Here are all of the errors at t presented with their steps and orders.

EOT foreach $this_steps ( sort keys %$summary_table ) { foreach $this_order ( sort keys %{$summary_table->{$this_steps}} ) { print <<"EOT"; EOT } print <<"EOT"; EOT } # # Print summary footer and page footer # print <<"EOT";
steps order error at t
$this_steps $this_order $summary_table->{$this_steps}{$this_order}
 
EOT }