MathGroup Archive 2000

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

Search the Archive

RE: Functional Expression Meaning (was:A Functional Expression Trick)

  • To: mathgroup at smc.vnet.net
  • Subject: [mg23885] RE: Functional Expression Meaning (was:[mg23859] A Functional Expression Trick)
  • From: Wolf Hartmut <hwolf at debis.com>
  • Date: Thu, 15 Jun 2000 00:51:22 -0400 (EDT)
  • Sender: owner-wri-mathgroup at wolfram.com

Dear David,

please see my answer below  >>>>

	-----Original Message-----
	From:	David Park [SMTP:djmp at earthlink.net]
To: mathgroup at smc.vnet.net
	Sent:	Monday, June 12, 2000 7:18 AM
	To:	mathgroup at smc.vnet.net
	Subject:	[mg23859] A Functional Expression Trick

Dear MathGroup,

Mathematica provides for functional expressions, but the standard exposition
(Section 2.2.5 - Section 2.2.9 in the Mathematica Book) does not make it
easy to work with them. The principal problem is that an expression of pure
functions is not itself a pure function. Here are two pure functions:

f = #1*#3^2 & ;
g = Cos[#2]*#3 & ;

I defined these functions so that they use consistent variables. The slot
numbers refer to the same variables in the two functions. If we form an
expression from these pure functions, we obtain an object that is not easy
to work with.

fexpr = f*g^2 + 2*f + Sin[f*g]
2*(#1*#3^2 & ) + (Cos[#2]*#3 & )^2*(#1*#3^2 & ) +
  Sin[(Cos[#2]*#3 & )*(#1*#3^2 & )]

For example, try to evaluate:

fexpr[x, y, z]
2*(#1*#3^2 & ) + (Cos[#2]*#3 & )^2*(#1*#3^2 & ) +
   Sin[(Cos[#2]*#3 & )*(#1*#3^2 & )])[x, y, z]

You can try to use Through on this expression, but you probably won't like
the results. (I developed the PushThrough package to handle cases like this,
but now I am going to present a different method.) Or suppose we wish to
take derivatives of fexpr:

Derivative[1, 0, 1][fexpr][x, y, z]
Derivative[1, 0, 1][2*(#1*#3^2 & ) + (Cos[#2]*#3 & )^2*(#1*#3^2 & ) +
    Sin[(Cos[#2]*#3 & )*(#1*#3^2 & )]][x, y, z]

This won't evaluate because Mathematica expects fexpr to be a pure function
or function name. If we have defined our pure functions with consistent slot
numbers, then it is simple enough to convert the expression into a pure
function. Simply remove all the &s in the middle and put one at the end. The
following function does this:

funexpr[expr_] := Function[Evaluate[expr /. Function -> Identity]]

Now, it is very easy to evaluate expressions involving fexpr.

funexpr[fexpr][x, y, z]
2*x*z^2 + x*z^4*Cos[y]^2 + Sin[x*z^3*Cos[y]]

Derivative[1, 0, 1][funexpr[fexpr]][x, y, z]
4*z + 4*z^3*Cos[y]^2 + 3*z^2*Cos[y]*Cos[x*z^3*Cos[y]] -
  3*x*z^5*Cos[y]^2*Sin[x*z^3*Cos[y]]

There is another standard method for converting a functional expression into
a pure function but it involves much more typing and somewhat undermines the
convenience of functional expressions.

fgfunc = Function[{x, y, z}, f[x, y, z]*g[x, y, z]^2 + 2*f[x, y, z] +
     Sin[f[x, y, z]*g[x, y, z]]];

fgfunc[x, y, z]
2*x*z^2 + x*z^4*Cos[y]^2 + Sin[x*z^3*Cos[y]]

Derivative[1, 0, 1][fgfunc][x, y, z]
4*z + 4*z^3*Cos[y]^2 + 3*z^2*Cos[y]*Cos[x*z^3*Cos[y]] -
  3*x*z^5*Cos[y]^2*Sin[x*z^3*Cos[y]]

David Park
djmp at earthlink.net
http://home.earthlink.net/~djmp/ <http://home.earthlink.net/~djmp/> 

>>>>

There are several remarks to made:

(1) I would have liked to receive this as "Functional Expression Meaning",
such 
the  renaming of this thread:

If we have two functions (or Mappings, Operators) f and g what does 

	f g

mean after all? Nothing, we have to _define_ it!  So often this is short for

      Composition[f, g]        (beware sometimes it's Composition[g, f] !)

(this just to show the need for definition). When I studied physics (long
ago), 
we used f g (or f * g to be more explicit) as short for:

     (f * g)[x] ::= f[x] * g[x]

where "*" denotes an operator in the image-space.

Now here functions are lambda-expressions, so we have to build the 
lambda expression for (f * g) from those of f and g  *and keep the semantics

of the lambda expression*.

In his "Programming in Mathematica" (2nd ed., p.112) Roman Maeder 
describes the latter as 

	Function[x, body][arg]

is evaluated essentially as 

	ReleaseHold[ Hold[body] /.  Literal[x] -> arg]

(Literal now has become HoldPattern, regard: arg is evaluated before 
substitution). So 

Function[ x, (body(f) /. HoldPattern[var(f)] ->x) * (body(g) /.
HoldPattern[var(g)] ->x)]

is to be the lambda expression for (f * g).

It's time to dig up a sample:

x = 1; y = 2; z = 3; x2 = 4; y2 = 5; z2 = 6;
(* to indicate possible errors *)

ffa = Function[{z, y, x}, Print["high"]; z *x^2];
gga = Function[{x2, y2, z2}, Print["there"]; Cos[y2]*z2];

ffgga = (Function[{x, y, z}, 
                 Evaluate[rh[(
                   Extract[ffa, {2}, Hold] /. 
                       {HoldPattern[z] :> x, HoldPattern[y] :> y,
HoldPattern[x] :> z}) *  (
                   Extract[gga, {2}, Hold] /. 
                       {HoldPattern[x2] :> x, HoldPattern[y2] :> y,
HoldPattern[z2] :> z}
                  )]]
              ]) /. rh -> ReleaseHold

Function[{x, y, z}, ReleaseHold[Hold[Print["high"]; x*z^2] * 
                                                  Hold[Print["there"];
Cos[y]*z]]]

(Of course the new arguments have not to be evaluated here!) 
We test it:

ffgga[x, y, z]

"high"
"there"
27 Cos[2]

ffa[x, y, z] * gga[x, y, z]

"high"
"there"
27 Cos[2]


(comment: This procedure was done as to keep the semantics for certain,
I'd more like to program it as:

ffgga = Function[{x, y, z}, Times[#1, #2]] & @@ 
              {Extract[ffa, {2}, Unevaluated] /. 
                   {HoldPattern[z] :> x, HoldPattern[y] :> y, HoldPattern[x]
:> z},
               Extract[gga, {2}, Unevaluated] /. 
                   {HoldPattern[x2] :> x, HoldPattern[y2] :> y,
HoldPattern[z2] :> z}}

Function[{x, y, z}, (Print["high"]; x*z^2) * (Print["there"]; Cos[y]*z)]

/comment)

Now the simple expression ...

ffgga2 = Function[{x, y, z}, ffa[x, y, z] gga[x, y, z]]

Function[{x, y, z}, ffa[x, y, z] gga[x, y, z]]

... certainly keeps the semantics

ffgga2[x, y, z]

"high"
"there"
27 Cos[2]

(the only difference to ffgga is, that this won't work any longer after the
definitions of ffa or gga have been removed)

Now clearly for "pure" functions 

fa = (Print["high"]; #1*#3^2) &

(Print["high"]; #1*#3^2) & 

ga = (Print["there"]; Cos[#2]*#3) &

(Print["there"]; Cos[#2]*#3) &

...

fga2 = Function[{x, y, z}, fa[x, y, z] ga[x, y, z]];

fga2[x, y, z]

"high"
"there"
27 Cos[2]

continues to work; but also the direct method (the variables are Slot[1], 
Slot[2], etc. and the body is in the first part):

fga = Function[{x, y, z}, 
        Times[#1, #2]] & @@ ({Extract[fa, {1}, Unevaluated],
          Extract[ga, {1}, Unevaluated]} /. {#1 :> x, #2 :> y, #3 :> z})

fga[x, y, z]

"high"
"there"
27 Cos[2]

(comment: of course this could then be simplified to 

fga = Function @@ Hold[Times[#1, #2]] & @@ {Extract[fa, {1}, Unevaluated],
      Extract[ga, {1}, Unevaluated]}

(Print["high"]; #1*#3^2) * (Print["there"]; Cos[#2]*#3) &

/comment)

Your solution however has a problem

fg = Function[Evaluate[fa ga /. Function -> Identity]]

"high"
"there"
Cos[#2]*#1*#3^3 & 

fg[x, y, z]

27 Cos[2]

so you loose something!  But I wanted to pick up your idea, so 
this repairs:

fga = ReleaseHold[Evaluate[fa * ga /. Function -> Hold] &]

(Print["high"]; #1*#3^2)*(Print["there"]; Cos[#2]*#3) & 

fga[x, y, z]

"high"
"there"
27 Cos[2]

And for fa * ga you should be able to insert any (algebraic) expression 
containing pure functions.

The more serious drawback  seems to be that lambda expressions cannot 
be treated that way. This can be repaired too:

Off[Pattern::"patv"]

makeFunFromExpr[expr_] := 
  ReleaseHold[
    Evaluate[expr /. {Function[({var__} | var_), body_] :> 
              Block[{var}, 
                Hold[body] /. 
                  Thread[Rule[{var}, 
                      Array[Slot, {Length[{var}]}]]]], 
            Function -> Hold}] &]

ffga = makeFunFromExpr[ffa ga]

(Print["high"]; #1*#3^2)*(Print["there"]; Cos[#2]*#3) & 

{ffa, ga}

{Function[{z, y, x}, Print["high"]; z*x^2], 
  (Print["there"]; Cos[#2]*#3) & }

ffga[x, y, z]

"high"
"there"
27 Cos[2]


Kind regards, your
	Hartmut Wolf


  • Prev by Date: Re: Newbie question: pairswise function application
  • Next by Date: Re: Integral evaluation bug?
  • Previous by thread: RE: Functional Expression Meaning (was:A Functional Expression Trick)
  • Next by thread: RE: Functional Expression Meaning (was:A Functional Expression Trick)