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); parse_IC_mgr:-parse_IC(ode,func,IC); IF hint is given THEN IF ode_order =1 THEN latex,solver_name,solution := first_order_ode_solver(ode,y(x),IC,hint); ELIF ode_order =2 THEN latex,solver_name,solution := second_order_ode_solver(ode,y(x),IC,hint); ELSE ERROR; -- hint is only now supported for first and second order, not higher END IF; ELSE -- no hint -- 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); FOR each factor DO IF ode_order=1 THEN latex,solver_name,solution := first_order_ode_solver(factor,y(x),IC,""); ELIF ode_order=2 THEN latex,solver_name,solution := second_order_ode_solver(factor,y(x),IC,""); ELSE latex,solver_name,solution := higher_order_ode_solver(factor,y(x),IC,""); END IF; END LOOP; END IF; RETURN latex, solver_used, solution; END proc;
The following is the main module for first order ode. Similar one for second order and similar one for higher order.
first_order_ode_solver:=proc(ode,y(x),IC,hint) IF hint is given THEN latex,solution := CALL the solver given in hit(ode,y(x),IC); ELSE -- check the ode type and call the lower level solver to solve it. IF first_order_ode_quadrature:-is_quadrature(ode,y(x)) THEN solutions := first_order_ode_quadrature:-dsolve(ode,y(x),IC); solutions := FIRST_ORDER_POST_PROCESS(solutions,ode,y(x),IC); IF list of solution not empty THEN RETURN solutions --done END IF END IF IF first_order_linear:-is_linear(ode,y(x)) THEN solution := first_order_ode_linear:-dsolve(ode,y(x),IC); solution := FIRST_ORDER_POST_PROCESS(solution,ode,y(x),IC); IF list of solution not empty THEN RETURN solutions --done END IF END IF IF ... same for all other first order solvers. There are 16 solvers now. . . . END IF END proc;
The following is the post processing function for first order, called after each specific solver have generated the solutions.
FIRST_ORDER_POST_PROCESS:=proc(solutions,ode,y(x),IC) -- This is called after each specific found the solution. -- Each solver only find the solution and it does not do anything else. -- it takes as input list of solutions found, and returns list of solutions -- after post processing. IF initial condition are given THEN FOR each solution found DO Update solution for initial conditions (this resolves constant of integration) END LOOP END IF FOR each solution DO IF solution is implicit then convert to explicit if possible and if solution remains valid against the ode and IC's if any. This means the solution if not already explicit, can remain implicit. END IF END LOOP FOR each solution DO Verify solution using odetest. IF not verified THEN remove solution. END IF END LOOP RETURN solutions (this could be empty list if solution(s) could not be verified.) END proc;