Chapter 1
Design of the ode solver program

This gives high level view of my differential equations solver program which is in development for academic use. The program design is based on top-down modular design.

There are a number of public API’s. The main API is dsolve(). But there are other API’s such as for finding eigenvalues and eigenvectors.

This diagram shows the top level design

The following is the pseudo code of the dsolve() procedure. This is one of main calls into the main module for solving a single differential equation. It returns back all solutions found.

dsolve:=proc(ode,y(x),IC,hint::string) 
 
-- This CALL validates the ode itself. IC are validated by each separate 
-- module below this throws parse error if any fail 
ode_MGR:-parse_ode(ode); 
ode_order := ode_MGR:-:-get_ode_order(ode); 
 
-- parse and validate IC. This throws error if any fails 
IF ode_order =1 then 
   first_order_ode:-parse_IC(ode,y(x),IC); 
ELIF ode_order=2 then 
   second_order_ode:-parse_IC(ode,y(x),IC); 
ELSE 
   higher_order_ode:-parse_IC(ode,y(x),IC); 
END IF 
 
-- the following factors ode if possible. For example for y''*y'=0 gives 
-- y''=0 and y'=0 factors. If not possible to factor, ode itself is only 
-- factor. in 99% of the times, ode do not factor and ode_factors list 
-- will just contain the original ode. But this makes it much easier 
-- to solve an ode if it can be factored. 
 
ode_factors := factor_ode(ode); 
 
-- This finds general and any singular solutions if any 
solutions_found :=  process_factors(ode,y(x),IC,hint,ode_factors) 
 
-- Update solutions for IC 
solutions_found :=  update_solutions_for_IC(solutions_found,y(x),IC) 
 
-- Finally, check solutions. Throw away ones that do not verify 
-- the ODE or IC 
 
solutions_found :=  verify_solutions_against_ode_and_IC(solutions_found,ode,y(x),IC) 
 
RETURN solutions_found
 

The following procedure is the main dispatcher.

It takes in the ode factors after being parsed with the initial conditions also parsed and verified and dispatches each to the correct solver depending on the ode order.

Its input is the original ode and all the factors found. Most of the time there are no factors and only the ode itself is its own factor. It returns back set of the solutions found.

process_factors:=proc(ode,y(x),IC,hint::string,ode_factors::list) 
 
solutions_found := {}; 
 
FOR current_factor in ode_factors DO -- must have at least one 
 
    -- possible to have factor not ode. Example x*y'=0, only factor is y'=0 
    -- and x factor is ignored. 
    IF current_factor has y THEN 
       -- find ode order to know which module to call. 
       ode_order := ode_MGR:-:-get_ode_order(current_factor); 
 
       IF ode_order = 0 then -- algebraic factor 
          -- handle case of factor has only y and no y'. For example y*y'=0 
          -- or cos(y)*y'=0, then factors are  cos(y)=0 and y'=0 and so on. 
          -- solutions to algebric factors have no consant of integration 
          -- but must still satisfy original ode and initial conditions. 
          solution := SOLVE(current_factor=0,y(x)) 
          -- only keep if it satisfies original ode and IC if any 
          IF solution does not satisfy ode or does not satisfy IC THEN 
             solution:={}; 
          END IF; 
 
       ELIF ode_order = 1 then 
          solution := first_order_ode:-dsolve(current_factor,y(x),IC,hint); 
       ELIF ode_order = 2 then 
          solution := second_order_ode:-dsolve(current_factor,y(x),IC,hint); 
       ELSE 
          solution := higher_order_ode:-dsolve(current_factor,y(x),IC,hint); 
       FI; 
 
       -- collect solutions and remove duplicates 
       solutions_found := solutions_found UNION solution; 
    END IF; 
END DO; 
 
RETURN solutions_found 
END proc;