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