3.13 How to parse a single ode?

The following function takes in a single ode and parses it to verify it is valid. It returns back 3 values. The dependent variable, the independent variable and the ode order.

#added 12/8/2022. 
interface(warnlevel=4); 
kernelopts('assertlevel'=2): 
 
parse_single_ode:=proc(ode::`=`)::symbol,symbol,integer; 
#parses single ode. returns back  dep_var,indep_var,ode_order 
#throws exception when it detects parsing errors 
 
local func; 
local y,x; 
local dep_variables_found::list,item; 
local the_order; 
 
func:=PDEtools:-Library:-GetDepVars("not given",ode,onlydifferentiatedfunctions=true); 
if nops(func)=0 then 
   error ("not differential equation ",ode); 
fi; 
 
func := func[1]; 
 
if nops(func)<>1 then 
   error("Parsing error, dependent variable must contain one argument, found ", func); 
fi; 
 
y:=op(0,func); 
x:=op(1,func); 
 
#basic verification 
if not has(ode,y) then 
   error ("Supplied ode ",ode," has no ",y); 
fi; 
 
if not has(ode,x) then 
   error ("Supplied ode ",ode," has no ",x); 
fi; 
 
if not has(ode,func) then 
   error ("Supplied ode ",ode," has no ",func); 
fi; 
 
the_order := PDEtools:-difforder(ode,x); 
#if the_order=0 then 
#   error ("No derivative found in ",ode,". Input is not differential equation"); 
#fi; 
 
#note that the following call will also return y(x) if the input is not an ode 
#this will check that the dependent variable will show with SAME argument in the ode 
#i.e. if y(x) and y(t) show up in same ode, it will throw exception, which is what 
#we want. 
try 
   dep_variables_found := PDEtools:-Library:-GetDepVars([y],ode); 
catch: 
   error lastexception; 
end try; 
 
#now go over dep_variables_found and check the independent variable is same as x 
#i.e. ode can be y'(z)+y(z)=0 but function is y(x). 
for item in dep_variables_found do 
    if not type(item,function) then 
       error("Parsing error. Expected ",func," found ",item," in ode"); 
    else 
       if op(1,item) <> x then 
          error("Parsing error. Expected ",func," found ",item," in ode"); 
       fi; 
    fi; 
od; 
 
#now go over all indents in ode and check that y only shows as y(x) and not as just y 
#as the PDEtools:-Library:-GetDepVars([_self:-y],ode) code above does not detect this. 
#i.e. it does not check  y'(x)+y=0 
 
if numelems(indets(ode,identical(y))) > 0 then 
   error("Parsing error, Can not have ",y," with no argument inside ",ode); 
fi; 
 
return y,x,the_order; 
end proc:
 

To use do

y,x,the_order := parse_single_ode(diff(y(x),x)+y(x)=0);
 

An alternative to the above is to pass the dependent function itself as well as the ode. This is what I do myself in my ode solver. Like this

parse_single_ode:=proc(ode::`=`,func::function(name))::symbol,symbol,integer; 
#parses single ode. returns back  dep_var,indep_var,ode_order 
#throws exception when it detects parsing errors 
 
local y,x; 
local dep_variables_found::list,item; 
local the_order; 
 
    if nops(func)<>1 then 
       error("Parsing error, dependent variable must contain one argument, found ", func); 
    fi; 
 
    y:=op(0,func); 
    x:=op(1,func); 
 
    #basic verification 
    if not has(ode,y) then 
       error ("Supplied ode ",ode," has no ",y); 
    fi; 
 
    if not has(ode,x) then 
       error ("Supplied ode ",ode," has no ",x); 
    fi; 
 
    if not has(ode,func) then 
       error ("Supplied ode ",ode," has no ",func); 
    fi; 
 
    the_order := PDEtools:-difforder(ode,x); 
 
    #note that the following call will also return y(x) if the input is not an ode 
    #this will check that the dependent variable will show with SAME argument in the ode 
    #i.e. if y(x) and y(t) show up in same ode, it will throw exception, which is what 
    #we want. 
    try 
       dep_variables_found := PDEtools:-Library:-GetDepVars([y],ode); 
       #print("dep_variables_found=",dep_variables_found); 
    catch: 
       error lastexception; 
    end try; 
 
    #now go over dep_variables_found and check the independent variable is same as x 
    #i.e. ode can be y'(z)+y(z)=0 but function is y(x). 
    for item in dep_variables_found do 
        if not type(item,function) then 
           error("Parsing error. Expected ",func," found ",item," in ode"); 
        else 
           if op(1,item) <> x then 
              error("Parsing error. Expected ",func," found ",item," in ode"); 
           fi; 
        fi; 
    od; 
 
    #now go over all indents in ode and check that y only shows as y(x) and not as just y 
    #as the PDEtools:-Library:-GetDepVars([_self:-y],ode) code above does not detect this. 
    #i.e. it does not check  y'(x)+y=0 
 
    if numelems(indets(ode,identical(y))) > 0 then 
       error("Parsing error, Can not have ",y," with no argument inside ",ode); 
    fi; 
 
    return y,x,the_order; 
end proc:
                                                                                  
                                                                                  
 

To use do the same as before, but need to add \(y(x)\) as second argument. Like this

y,x,the_order := parse_single_ode(diff(y(x),x)+y(x)=0, y(x));