Uniform design
- To: mathgroup at smc.vnet.net
- Subject: [mg48066] Uniform design
- From: ab_def at prontomail.com (Maxim)
- Date: Mon, 10 May 2004 06:51:22 -0400 (EDT)
- Sender: owner-wri-mathgroup at wolfram.com
In some cases the interface of Mathematica functions seems to be poorly thought out. For example, what formats are allowed in the equation solving functions? This seems to vary a lot: In[1]:= Solve[{{x, y} == {1, 1}}] NSolve[{{x, y} == {1, 1}}] DSolve[{{y'[x], y[0]} == {y[x], 1}}, y, x] FindRoot[{{x, y} == {1, 1}}, {x, 2}, {y, 2}] FindRoot[{{x, y} == {1, 1}}, {x, 2}, {y, 2}, Jacobian -> {{1, 0}, {0, 1}}] Out[1]= {{x -> 1, y -> 1}} Solve::elist: List encountered during logical expansion of {-1.000000000000000000000000000000<<101>>000000000000000000 + x, <<1>>}. Out[2]= NSolve[{{x, y} == {1, 1}}] DSolve::litarg: To avoid possible ambiguity, the arguments of the dependent variable in {{y'[x], y[0]} == {y[x], 1}} should literally match the independent variables. Out[3]= DSolve[{{y'[x], y[0]} == {y[x], 1}}, y, x] FindRoot::njnum: The Jacobian is not a matrix of numbers at{x, y} = {2., 2.}. Out[4]= {x -> 2., y -> 2.} Out[5]= {x -> 1., y -> 1.} Solve and FindRoot thread Equal over lists, other functions don't. FindRoot seems to forget to set up the jacobian correctly in that case, though. Actually, sometimes DSolve accepts lists too, which makes things worse: In[6]:= DSolve[{y'[x], y[x]} == {y[x], 0}, y, x] DSolve[{y'[x], y[x]} == {y[x], 0} // Thread, y, x] Out[6]= {{y -> Function[{x}, C[1]]}} DSolve::overdet: The system has fewer dependent variables than equations, so is overdetermined. Out[7]= DSolve[{y'[x] == y[x], y[x] == 0}, y, x] The second DSolve just fails to solve the trivial system, but the first one gives incorrect answer. It should be remembered that FindRoot and NDSolve can work with vector-valued functions, but I think it's possible to distinguish between x=={1,1} (which means that x is a vector) and equality between objects which have the same dimensions. Trying to give 'vector' input to other functions leads to further problems: In[8]:= DSolve[y'[x] == {1, 1}, y, x] DSolve[y'[x] == {1, 2}, y, x] Out[8]= {{y -> Function[{x}, x + C[1]]} Out[9]= {} The results are different, but it's hard to tell which one makes less sense. Then there's the question of how Solve and NSolve determine the variables to solve for: In[10]:= Solve[Sin[x]/x == 1] NSolve[Sin[x]/x == 1] Solve::tdep: The equations appear to involve the variables to be solved for in an essentially non-algebraic way. Out[10]= Solve[Sin[x]/x == 1] NSolve::infsolns: Infinite solution set has dimension at least 1. Returning intersection of solutions with <<1>>. Out[11]= {{x -> 5.17616, Sin[x] -> 5.17616}} Solve decides that there's only one variable x, NSolve treats x and Sin[x] as separate variables. I know that the question of what should be considered a variable can be turned into a scholastic discussion, I just wish that Solve/NSolve treated this issue in a more uniform way. And that's still not all, there's a lot of similar issues: can the list of equations include True? (Yes for Solve, no for other functions.) Can Sin[x] be used as a variable? (Yes for Solve/NSolve, no for FindRoot.) Such discrepancies will inevitably lead to problems which are much harder to trace if they appear in the program code: In[12]:= Reduce[x > 0, {x, x}] Out[12]= False Apparently, one of the reasons for this kind of problems is the absence of standard routines that would handle the input -- analyze the structure of the equations set, find independent variables, and so on. If every Mathematica function has to implement the parsing separately, then it's impossible to achieve uniform behaviour. Authors of Mathematica add-on packages are also on their own here. But even apart from having such 'SDK' routines, there are other ways to alleviate this problem: first, to describe the expected input format more clearly in the documentation; second, to provide the user with better diagnostics -- messages like DSolve::litarg in the examples above don't explain much. If you try FindRoot[{x==1,True}, {x,0}] in version 5.0, you'll get an especially helpful message: "FindRoot::eqns: -- Message text not found --". Maxim Rytin m.r at prontomail.com