Re: Defining two functions at once?

*To*: mathgroup at smc.vnet.net*Subject*: [mg70757] Re: [mg70730] Defining two functions at once?*From*: Andrzej Kozlowski <akoz at mimuw.edu.pl>*Date*: Thu, 26 Oct 2006 02:39:01 -0400 (EDT)*References*: <200610250539.BAA28821@smc.vnet.net> <78AA9A16-9EF9-4717-9E52-3BF779D34077@mimuw.edu.pl>

On 25 Oct 2006, at 20:18, Andrzej Kozlowski wrote: > > On 25 Oct 2006, at 14:39, AES wrote: > >> I want to define two functions at once, where both of their values >> depend on the same two variables, and both of their values come >> out of a >> single two-dimensional FindRoot which I'd rather not evaluate twice. >> >> The following approach seems to work fine for a *single* function >> >> f[x_, y_] := Module[{}, >> myEqns = {f1 - g1 == x1 + 3y1, f1 + g1 == 2x1 - 7y1}; >> myValues = {x1 -> x, y1 -> y}; >> mySolns = FindRoot[ myEqns /. myValues, {f1, 0} , {g1, 0}]; >> f1 /. mySolns] >> >> But if I try to define two functions at once by replacing the >> first and >> last lines with >> >> {f[x_, y_], g[x_,y_]} := Module[{}, >> myEqns = {f1 - g1 == x1 + 3y1, f1 + g1 == 2x1 - 7y1}; >> myValues = {x1 -> x, y1 -> y}; >> mySolns = FindRoot[ myEqns /. myValues, {f1, 0} , {g1, 0}]; >> {f1, g1} /. mySolns] >> >> I get a message about "shapes not being the same". In fact, if I >> just >> make the first and last lines even a single element list, e.g. >> >> {f[x_, y_]} := Module[{}, >> myEqns = {f1 - g1 == x1 + 3y1, f1 + g1 == 2x1 - 7y1}; >> myValues = {x1 -> x, y1 -> y}; >> mySolns = FindRoot[ myEqns /. myValues, {f1, 0} , {g1, 0}]; >> {f1} /. mySolns] >> >> this doesn't work either. >> >> If a module supposedly returns the result of its (compound) >> expression, >> and the final term in that expression is a list, shouldn't the final >> example work? More important (to me anyway): Is there a simple >> way to >> define two functions that use a shared FindRoot evaluation in a >> way that >> (a) evaluates the FindRoot only once, and (b) involves only a single >> compound expression of some sort? >> > > > I know this is not really relevant here, but I feel I should > mention the fact that there is absolutely no point in using Module > without any local variables; if you do not need local variables you > will do better to enclose the right hand side in parentheses (or > use explicit Composition[....,....,...]). > Now to answer your question. You can only use lists with SetDelayed > with lists if both sides have the head List *before evaluation* > and the lists have the same shape. However, before evaluation your > right hand side has Head Module, before Evaluation so your approach > can't work. This problem would disappear if you used Set (=) > instead of SetDelayed but another would take its place: the right > hand side would be evaluated immediately, but then FindRoot would > produce an error since it would no be able to solve the equations > without numerical values for x and y. > > The simplest way do deal with your problem requires a lot of > typing (or at east copying and pasting): > > {f[x_, y_], g[x_, y_]} := {Module[{myEqns, myValues, mySolns, x1, > y1, f1, g1}, > myEqns = {f1 - g1 == x1 + 3*y1, f1 + g1 == 2*x1 - 7*y1}; > myValues = {x1 -> x, y1 -> y}; mySolns = FindRoot[myEqns /. > myValues, {f1,0},{g1,0}];f1 /. mySolns],Module[{myEqns, myValues, > mySolns}, > myEqns = {f1 - g1 == x1 + 3*y1, f1 + g1 == 2*x1 - 7*y1};myValues = > {x1 -> x, y1 -> y};mySolns = FindRoot[myEqns /. myValues, {f1, 0}, > {g1, 0}]; g1 /. mySolns]} > > This long-winded method will indeed define two functions in "one go": > > In[3]:= > Through[{f,g}[1,2]] > > Out[3]= > {-2.5,-9.5} > > Actually, I can see another way, which uses only one Module, but as > I do not think it is any better than the above one, I will only > describe it in words and leave implementation to anyone who sees > more value in it than I do. Basically the idea is first, to > replace SetDelayed by Set, so that the right hand side is evaluated > immediately and then to re-write the right hand side so that it > will evaluate to a list with two elements. In order to do this you > would need to prevent FindRoot and Replace from trying to evaluate > prematurely. This could be done, for example, by using a list of > two conditional statements of the form {If[Element[Complexes, x|y], > FindRoot....., If[Element[Complexes,x|y],FindRoot.....}. In other > words the right hand side should immediately evaluate to a list of > two conditional expressions, which will return the values of f[x,y] > and g[x,y] when x and y are numerical. > > Andrzej Kozlowski > > After reading your message more carefully for the second time I realized that you were concerned (naturally!) to avoid double evaluation of FindRoot etc. Actually, this is quite easy to do, while avoiding the use of global variables by means of the following somewaht unconventional use of Module (or Block) Module[{myEqns, myValues, mySolns, x1, y1, f1, g1}, {f[x_, y_], g[x_, y_]} := { myEqns = {f1 - g1 == x1 + 3*y1, f1 + g1 == 2*x1 - 7*y1}; myValues = {x1 -> x, y1 -> y}; mySolns = FindRoot[myEqns /. myValues, {f1, 0}, {g1, 0}]; f1 /. mySolns, g1 /. mySolns}] Now as before we get: In[2]:= Through[{f,g}[1,2]] Out[2]= {-2.5,-9.5} Note that FindRoot was evaluated only once, as you had wished. Andrzej Kozlowski Tokyo, Japan

**References**:**Defining two functions at once?***From:*AES <siegman@stanford.edu>