Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Non-sequential composition of pure functions

75 views
Skip to first unread message

Earl Mitchell

unread,
Aug 22, 2012, 2:26:03 AM8/22/12
to

Hi All,

I have a list of pure functions (If[Conditional[#[[1]]],Action]&
statements) and I want to compose them into one large pure function
If[FirstConditional[#[[1]]]&&SecondConditional[#[[6]]]&&ThirdConditional[#[[foo]]],Action]&.
They are to be applied to a list of values, and the conditionals checked
for multiple columns for a given element of a list.

I'm having problems joining these things together - to the point that I've
considered converting them all to strings and doing the tedious
(hackie) string manipulations to get the final function in the right form.
Any recommendations on how to do this? I found Composition[] but it nests
the functions - and I want to combine them.

Thanks!

Mitch

Ray Koopman

unread,
Aug 22, 2012, 5:20:45 AM8/22/12
to
In[1]:= f1 = If[c1@#, a1]&;
f2 = If[c2@#, a2]&;
f3 = If[c3@#, a3]&;

In[4]:= If[And @@ MapThread[#1@#2&,
{ {f1,f2,f3}[[All,1,1,0]], {x1,x2,x3} }], action]

Out[4]= If[c1[x1] && c2[x2] && c3[x3], action]

awnl

unread,
Aug 22, 2012, 5:21:05 AM8/22/12
to
Hi,
it is not clear what you mean by "combining" the functions, but whatever
you want to do, I would never suggest to convert to string and back. It
is one of the great strengths of Mathematica that you can treat
Mathematica code just a any other expression, although the evaluation
scheme makes it somewhat tricky to manipulate code without evaluating
it. Here is an example which does something along the lines you described:

condlist={If[#[[1]]>0,Print["1"]]&,If[#[[2]]>0,Print["2"]]&}

If@@@(Function@@{Join[
And@@@Hold@@{Flatten[Hold@@Cases[condlist,Function[If[c_,a_]]:>Hold[c],{1}]]},
Hold[Print["3"]]
]})

There might be somewhat simpler or clearer ways to do such
manipulations. Which "tricks" you use to avoid the evaluation of the
code you manipulate are also a matter of taste, it's usually some
combination of Hold, Unevaluated, With that you'll need. If you want a
solution for your very problem, you would need to send a full example of
input and desired output...

hth,

albert

awnl

unread,
Aug 23, 2012, 2:51:28 AM8/23/12
to
Hi Earl,
>
> This is very close to what I need. ... The exact
> problem I have is this ...:
>
> I have the following list of functions:
>
> list1={If[#1[[4]] <= 6, 4.52] &, If[#1[[4]] <= 0, 4.47] &, If[#1[[5]] <= 0,
> 4.40] &,
> If[#1[[1]] <= 0, 4.02`] &, If[#1[[3]] <= 0, 4.30] &}
>
> I want to produce the following list of functions:
>
> targetlist= {
> If[#1[[4]] <= 6, 4.52] &,
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0), 4.47] &,
>
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0), 4.40] &,
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0) && (#1[[1]] <=
> 0), 4.02] &,
>
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0) && (#1[[1]] <=0) &&
> (#1[[3]] <= 0), 4.30] &
>
> }
>
> Quick aside - I recognize that given the function in position two, the
> function in position one is irrelevant (redundant). If the composition
> algorithm could check for and discard any *sequential* irrelevancies that
> would be even better. If, however, the third function were put sequentially
> between functions one and two, then all three statements would be relevant.

The following should do what you want. I decided to store the
intermediate results as I think it is somewhat easier to follow what
happens. This is just what I came up with at first try, as usual there
are plenty possibilities to achieve the same thing, some of which might
be much more elegant. The code is also not bullet proof, but I didn't
want to introduce additional complexity for making it more safe or
general. Anyway I hope it is good enough to get you started:

(*extract the held conditions and bodies (in this case just values) *)
heldConditions=Cases[list1,Function[If[c_,_]]:>Hold[c]]
heldBodies=Cases[list1,Function[If[_,b_]]:>Hold[b]]

(* create the "accumulated" conditions, still wrapped with Hold *)
accumulatedConditions=ReplaceAll[
Hold/@Rest[FoldList[And,True,heldConditions]],
Hold[LessEqual[x___]]:>LessEqual[x]
]

(* finally compose the resulting functions from the accumulated
conditions and the stored "bodies" *)
targetList=Function/@Flatten/@Hold@@@Transpose[{accumulatedConditions,heldBodies}]/.Hold->If

hth,

albert

Ray Koopman

unread,
Aug 23, 2012, 2:52:48 AM8/23/12
to
----- On Wed, Aug 22, 2012 at 08:04 AM, Earl Mitchell <earl.j....@gmail.com> wrote:
> Thanks Ray,
>
> This doesn't quite answer my question (though it is due to the lack of
> clarity I had in my original example). The exact problem I have is this:
>
> I have the following list of functions:
>
> list1={If[#1[[4]] <= 6, 4.52] &, If[#1[[4]] <= 0, 4.47] &, If[#1[[5]] <= 0,
> 4.40] &,
> If[#1[[1]] <= 0, 4.02`] &, If[#1[[3]] <= 0, 4.30] &}
>
> I want to produce the following list of functions:
>
> targetlist= {
> If[#1[[4]] <= 6, 4.52] &,
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0), 4.47] &,
>
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0), 4.40] &,
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0) && (#1[[1]] <=
> 0), 4.02`] &,
>
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0) && (#1[[1]] <= 0) && > (#1[[3]] <= 0), 4.30] &
>
> }
>
> Quick aside - I recognize that given the function in position two, the
> function in position one is irrelevant (redundant). If the composition
> algorithm could check for and discard any *sequential* irrelevancies that
> would be even better. If, however, the third function were put sequentially
> between functions one and two, then all three statements would be relevant.
>
> Thanks!
>
> Mitch

In[1]:= list1 = {
If[#[[4]] <= 6, 4.52]&,
If[#[[4]] <= 0, 4.47]&,
If[#[[5]] <= 0, 4.40]&,
If[#[[1]] <= 0, 4.02]&,
If[#[[3]] <= 0, 4.30]&};

In[2]:= f =
Table[With[{ positions = list1[[Range@j,1,1,1,2]],
comparands = list1[[Range@j,1,1,2]],
result = list1[[ j,1,2]] },
Function[
If[Inner[LessEqual,#[[positions]],comparands,And], result]]],
{j,5}]

Out[2]=
{If[Inner[LessEqual, #1[[{4}]], {6}, And], 4.52]&,
If[Inner[LessEqual, #1[[{4,4}]], {6,0}, And], 4.47]&,
If[Inner[LessEqual, #1[[{4,4,5}]], {6,0,0}, And], 4.4]&,
If[Inner[LessEqual, #1[[{4,4,5,1}]], {6,0,0,0}, And], 4.02]&,
If[Inner[LessEqual, #1[[{4,4,5,1,3}]], {6,0,0,0,0}, And], 4.3]&}

In[3]:= f[[#]]@{x1,x2,x3,x4,x5}& /@ Range@5

Out[3]=
{If[x4 =E2=89=A4 6, 4.52],
If[x4 =E2=89=A4 6 && x4 =E2=89=A4 0, 4.47],
If[x4 =E2=89=A4 6 && x4 =E2=89=A4 0 && x5 =E2=89=A4 0, 4.4],
If[x4 =E2=89=A4 6 && x4 =E2=89=A4 0 && x5 =E2=89=A4 0 && x1 =E2=89=A4 0, 4.02],
If[x4 =E2=89=A4 6 && x4 =E2=89=A4 0 && x5 =E2=89=A4 0 && x1 =E2=89=A4 0 && x3 =E2=89=A4 0, 4.3]}

>
> On Wed, Aug 22, 2012 at 3:19 AM, Ray Koopman <koo...@sfu.ca> wrote:
>
>> On Aug 21, 11:26 pm, Earl Mitchell <earl.j.mitch...@gmail.com> wrote:
>>> Hi All,
>>>
>>> I have a list of pure functions (If[Conditional[#[[1]]],Action]&
>>> statements) and I want to compose them into one large pure function
>>>
>>> If[FirstConditional[#[[1]]]&&SecondConditional[#[[6]]]&&ThirdConditional[#[[foo]]],Action]&.
>>>
>>> They are to be applied to a list of values, and the conditionals checked
>>> for multiple columns for a given element of a list.
>>>
>>> I'm having problems joining these things together - to the point that
>>> I've considered converting them all to strings and doing the tedious
>>> (hackie) string manipulations to get the final function in the right form.
>>> Any recommendations on how to do this? I found Composition[] but it
>>> nests the functions - and I want to combine them.
>>>

Ralph Dratman

unread,
Aug 23, 2012, 2:53:41 AM8/23/12
to
I have developed some relevant techniques for handling this sort of
problem, but in order to suggest what to do, I need to see more
details of what the desired result should look like. Could you please
illustrate that with an example of (manually) combining two or three
pure functions, showing what you would like the resulting function to
look like?

Thank you.

Ralph Dratman


On Wed, Aug 22, 2012 at 5:19 AM, awnl <aw...@gmx-topmail.de> wrote:
> Hi,

Earl Mitchell

unread,
Aug 23, 2012, 2:54:28 AM8/23/12
to

Thanks Ray,

This doesn't quite answer my question (though it is due to the lack of
clarity I had in my original example). The exact problem I have is this:

I have the following list of functions:

list1={If[#1[[4]] <= 6, 4.52] &, If[#1[[4]] <= 0, 4.47] &, If[#1[[5]] <= 0,
4.40] &,
If[#1[[1]] <= 0, 4.02`] &, If[#1[[3]] <= 0, 4.30] &}

I want to produce the following list of functions:

targetlist= {
If[#1[[4]] <= 6, 4.52] &,
If[(#1[[4]] <= 6) && (#1[[4]] <= 0), 4.47] &,

If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0), 4.40] &,
If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0) && (#1[[1]] <=
0), 4.02`] &,

If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0) && (#1[[1]] <=0) &&
(#1[[3]] <= 0), 4.30] &

}

Quick aside - I recognize that given the function in position two, the
function in position one is irrelevant (redundant). If the composition
algorithm could check for and discard any *sequential* irrelevancies that
would be even better. If, however, the third function were put sequentially
between functions one and two, then all three statements would be relevant.

Thanks!

Mitch
Mitch



On Wed, Aug 22, 2012 at 3:19 AM, Ray Koopman <koo...@sfu.ca> wrote:

> On Aug 21, 11:26 pm, Earl Mitchell <earl.j.mitch...@gmail.com> wrote:

Sseziwa Mukasa

unread,
Aug 23, 2012, 3:07:26 AM8/23/12
to

On approach:

Extract the list of conditions from the functions:

(Debug) In[49]:=
list = {(If[cond1[#[[1]]], action]) &, (If[cond2[#[[2]]],
action]) &, (If[cond3[#[[3]]], action]) &};

(Debug) In[50]:= list /. (If[cond_, action_] &) -> (cond &)

(Debug) Out[50]= {cond1[#1[[1]]] &, cond2[#1[[2]]] &,
cond3[#1[[3]]] &}

Then you can use Through and And to evaluate all the conditions:

(Debug) In[53]:= And @@
Through[(list /. (If[cond_, action_] &) -> (cond &))[{arg1, arg2,
arg3}]]

(Debug) Out[53]= cond1[arg1] && cond2[arg2] && cond3[arg3]

At this point all you need to do is extract the action from one of the
functions, or all of them if they are different, and perform based on the
result of the conditional. Putting it all together:

(Debug) In[55]:=
combineConditionalFunctions[functions_ {If[_, _] & ..},
arguments_ {__}] :=
Module[{performAction =
And @@ Through[(functions /. (If[cond_, action_] &) -> (cond &))[
arguments]],
action = functions[[1]] /. (If[_, action_]) & -> action},
If[performAction, action]]

(Debug) In[56]:= combineConditionalFunctions[list, {arg1, arg2, arg3}]

(Debug) Out[56]= If[
cond1[arg1] && cond2[arg2] && cond3[arg3], action$900]

Earl Mitchell

unread,
Aug 23, 2012, 8:50:53 PM8/23/12
to
I ended up getting the solution to this guy earlier in the thread. I've
resent it below for reference.

If anyone is interested in taking on a side-M project (creating an M
version of the RandomForest algorithm is the current task) send me a
personal e-mail at earl.j....@gmail.com.

This group is excellent, thanks again -

Mitch

On Wed, Aug 22, 2012 at 9:16 AM, Earl Mitchell <earl.j....@gmail.com>wrote:

> Thanks again - I think I got it. The solution - slightly modified from
> what Albert sent - was this (and if there are obvious improvements to what
> I do here I'd love to hear them, learning a lot even though I program in M
> every day!):
>
> originalconds = {If[#1[[4]] <= 6, 4.52] &,
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0), 4.47] &,
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0), 4.40] &,
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0) && (#1[[1]] <= 0),
> 4.02] &,
> If[(#1[[4]] <= 6) && (#1[[4]] <= 0) && (#1[[5]] <= 0) && (#1[[1]] <=
> 0) && (#1[[3]] <= 0), 4.30] &}
>
>
> out472:= Join[{originalconds[[1]]},
> Table[
> With[{
> condlist = Take[originalconds, i]
> },
> With[{
> action = First@Last[condlist /. If[c_, a_] :> (a) /. Function ->
> List]
> },
> If @@@ (Function @@ {Join[
> And @@@
> Hold @@ {Flatten[
> Hold @@ Cases[condlist, Function[If[c_, a_]] :> Hold[c],
> {1}]]},
> Hold[action]]})]], {i, 2, Length[originalconds]}]]
>
>
> out472= {If[#1[[4]] <= 6, 4.52] &,
> If[#1[[4]] <= 6 && (#1[[4]] <= 6 && #1[[4]] <= 0), 4.47] &,
> If[#1[[4]] <= 6 && (#1[[4]] <= 6 && #1[[4]] <= 0) && (#1[[4]] <= 6 &&
> #1[[4]] <= 0 && #1[[5]] <= 0), 4.4] &,
>
> If[#1[[4]] <=
> 6 && (#1[[4]] <= 6 && #1[[4]] <= 0) && (#1[[4]] <= 6 && #1[[4]] <=
> 0 && #1[[5]] <= 0) && (#1[[4]] <= 6 && #1[[4]] <= 0 && #1[[5]] <=
> 0 && #1[[1]] <= 0), 4.02] &,
> If[#1[[4]] <=
> 6 && (#1[[4]] <= 6 && #1[[4]] <= 0) && (#1[[4]] <= 6 && #1[[4]] <=
> 0 && #1[[5]] <= 0) && (#1[[4]] <= 6 && #1[[4]] <= 0 && #1[[5]] <=
> 0 && #1[[1]] <= 0) && (#1[[4]] <= 6 && #1[[4]] <= 0 && #1[[5]] <=
> 0 && #1[[1]] <= 0 && #1[[3]] <= 0), 4.3] &}
>
>
> Thanks again!
>
>
> Mitch

Ray Koopman

unread,
Aug 23, 2012, 8:51:47 PM8/23/12
to
On Aug 22, 11:52 pm, Ray Koopman <koop...@sfu.ca> wrote:
> [...]
>
> Out[3]=
> {If[x4 =E2=89=A4 6, 4.52],
> If[x4 =E2=89=A4 6 && x4 =E2=89=A4 0, 4.47],
> If[x4 =E2=89=A4 6 && x4 =E2=89=A4 0 && x5 =E2=89=A4 0, 4.4],
> If[x4 =E2=89=A4 6 && x4 =E2=89=A4 0 && x5 =E2=89=A4 0 && x1 =E2=89=A4 0, 4.02],
> If[x4 =E2=89=A4 6 && x4 =E2=89=A4 0 && x5 =E2=89=A4 0 && x1 =E2=89=A4 0 && x3 =E2=89=A4 0, 4.3]}

Sorry about that hi ascii. It should have been

Out[3]=
{If[x4 <= 6, 4.52],
If[x4 <= 6 && x4 <= 0, 4.47],
If[x4 <= 6 && x4 <= 0 && x5 <= 0, 4.4],
If[x4 <= 6 && x4 <= 0 && x5 <= 0 && x1 <= 0, 4.02],
If[x4 <= 6 && x4 <= 0 && x5 <= 0 && x1 <= 0 && x3 <= 0, 4.3]}

Earl Mitchell

unread,
Aug 23, 2012, 8:55:12 PM8/23/12
to
0 new messages