MathGroup Archive 2006

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Defining two functions at once?

  • To: mathgroup at smc.vnet.net
  • Subject: [mg70764] Re: [mg70730] Defining two functions at once?
  • From: Andrzej Kozlowski <akoz at mimuw.edu.pl>
  • Date: Thu, 26 Oct 2006 02:39:21 -0400 (EDT)
  • References: <200610250539.BAA28821@smc.vnet.net>

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



  • Prev by Date: Re: Defining two functions at once?
  • Next by Date: Re: Defining two functions at once?
  • Previous by thread: Defining two functions at once?
  • Next by thread: Re: Defining two functions at once?