So, I have made a rough layout of the main function that will be used to solve ODEs with the methods like neq_nth_order_linear_constant_coeff_homogeneous/nonhomogeneous, neq_nth_linear_symmetric_coeff_homogeneous/nonhomogeneous, special case non-linear solvers, etc.
Some notations used:
eqs: Equations, funcs: dependent variables, t: independent variable, wcc: weakly connected component, scc: strongly connected component
Introduction to helper functions that will be used(these are temporary names, parameters and return elements and may be changed if required):
1. match_ode:-
Parameters: eqs, funcs, t
Returns: dictionary which has important keys like: order(a dict that has func as a key and maximum order found as value), is_linear, is_constant, is_homogeneous, eqs, funcs.
2. component_division:-
Paramters: eqs, funcs
Returns: A 3D list where the eqs are first divided into its wccs and then into its sccs.
This function is suggested to be implemented later. So, until all the other solvers are not ready(tested and working), this function will just take eqs and return [[eqs]].
3. get_coeff_matrix:-
Parameters: eqs, funcs
Returns: coefficient matrix A(t) and f(t)
This function takes in a first order linear ODE and returns matrix A(t) and f(t) from X' = A(t) * X + f(t).
4. nth_order_to_first_order:-
Parameters: eqs, order
Returns: first order ODE with new introduced dependent variables.
And all the first order linear solvers mentioned above.
Now, besides the main function, there are two separate functions depending on whether the system of ODEs is linear or not, namely _linear_ode_sol and _non_linear_ode_sol.
1. _first_order_linear_ode_sol:-
Parameters: match dict(obtained earlier and maybe modified in ode_sol)
Returns: Dict with keys as func and value as its solution that solves the ODE.
Working: First, extracts A(t) and f(t) using get_coeff_matrix, then using match dict, identify which solver is required and solve the ODE if it is possible to do so. For example: Case where A(t) is not symmetric isn't solved.
2. _non_linear_ode_sol has similar Parameters and Returns but the function operates differently that's why it is essential to use a different function. But I don't have a clear understanding
of how to design _non_linear_ode_sol yet but here is what I have came up with: First match the condition where it is possible seperate out the independent variable to get a relationship
between the dependent variables and then finally, just use the special solver to solve the ODE.
Now, coming to the main function ode_sol(for now, I haven't considered initial values):-
Parameters: eqs, funcs, t
Returns: Solution in a dict form where func is the key and value is the solution for that corresponding func.
Working:
The steps of its working-
1. Preprocess the equations.
2. Get the match dict using match_ode function.
3. Convert nth order equations to first order equations using nth_order_to_first_order while storing the funcs seperately so that we can later filter out the dependent variables that were introduced in this step.
4. Get the 3D list of equations using component_division function.
5. Iterate through the wccs and solve and store solutions seperately but for sccs, first solve the first set of equations in a scc, then substitute the solutions found in the first set of the current scc to the second
set of current scc. Keep doing this until the all the sets for a particular scc is solved.
6. For solving a component, choose either _linear_ode_sol or _non_linear_ode_sol depending upon the set of equations to be solved.
7. Return a dict by taking out values from the solution obtained using all the dependent variables in funcs as there may be more variables introduced when we made the system into first order.
For now, this is what I have came up with. Obviously the order in which we will proceed is, build the basic layout of the main function and component_division will just increase the number of dimensions to 3 rudimentarily as we
will have to first ensure that the general solvers work well since working on both of them simultaneously will make it tough to pinpoint the errors. Along with that, non-linear solvers can be implemented later, we can just raise a
NotImplementedError for now till we have completed both the general linear solvers and the component_division and then add the special case solvers.