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
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