Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I am interested in threading a compiled function over multiple argument lists of different lengths.

I will explain this in two steps:

Suppose f is some function. Then one can define another function,

ppost[arg_, context_] := Apply[f[arg, ##] &, context]

which can be used as

In[2]:= ppost[a, {b, c}]

Out[2]= f[a, b, c]

or in a more complex scenario let,

In[3]:= argList = {{a1, b1}, {a2, b2, c2}};

In[4]:= mList = {{m1, n1}, {m2, n2, o2}};

In[5]:= contextList = {mList, y, z}

Out[5]= {{{m1, n1}, {m2, n2, o2}}, y, z}

We can thread the function over the argList and the contextList as follows:

In[6]:= Thread[ppost[argList, contextList]]

Out[6]= {f[{a1, b1}, {m1, n1}, y, z], 
         f[{a2, b2, c2}, {m2, n2, o2}, y, z]}

The above works, as needed.

Question: I need to do the same when f is a compiled function. As an example,

fc = Compile[{{arg, _Real, 1}, {c1, _Real, 1}, {c2, _Real}, {c3, _Real}},
  c3*arg + c2*c1
  ]

ppost1[arg_, context_] := Apply[fc[arg, ##] &, context]

In[9]:= nargList = {{1, 2}, {3, 4, 5}} // N;

In[10]:= nmList = {{6, 7}, {8, 9, 10}} // N;

In[11]:= ncontextList = {nmList, 50, 55} // N

Out[11]= {{{6., 7.}, {8., 9., 10.}}, 50., 55.}

In[12]:= ppost1[nargList[[1]], {nmList[[1]], 50, 55}]

Out[12]= {355., 460.}

So far, so good, but then the following does not work properly, and uses the uncompiled version.

In[14]:= Thread[ppost1[nargList, ncontextList]]

During evaluation of 
In[14]:= CompiledFunction::cfta: Argument {{1.,2.},{3.,4.,5.}} at position 1 
should be a rank 1 tensor of machine-size real numbers. >>

During evaluation of 
In[14]:= Thread::tdlen: Objects of unequal length in 
{{355.,460.},{565.,670.,775.}} cannot be combined. >>`

Out[14]= {{355., 460.}, {565., 670., 775.}}

So, how can I thread the compiled function over the arguments nargList, ncontextList?

share|improve this question
add comment

3 Answers 3

up vote 5 down vote accepted

I think your problem is equivalent to trying to get something like this

l := Power[2, 2]

f /@ l

return f[2]^f[2] instead of 4

You can control argument evaluation in MMA, for it to be either evaluated or not evaluated, but not half evaluated. If you wanted that you would have to either redesign your variables, or use things like replacement rules of OwnValues/DownValuess

In your case, you are expecting ppost1 to evaluate to fc, but fc not try to evaluate its arguments (until Thread had a chance to act)

If someone understood better than I did what your goal is, perhaps he can help you do it in some way

EDIT

Perhaps what you're looking for then can be achieved by masking the compiled function with a function that knows how to stay symbolically unevaluated

With[{cmp = 
   Compile[{{arg, _Real, 1}, {c1, _Real, 
      1}, {c2, _Real}, {c3, _Real}}, c3*arg + c2*c1]},
 fc[arg : {___Real}, c1 : {___Real}, c2_Real, c3_Real] :=
  cmp[arg, c1, c2, c3]
 ]
share|improve this answer
    
Rojo, please see my answer above, especially the last part. Do you think my understanding of the question is correct? –  Mr.Wizard Feb 7 '12 at 4:41
    
@Spartacus I think you probably got it. But perhaps he needs that ppost function for something. He'll probably tell us soon –  Rojo Feb 7 '12 at 4:52
    
please see this post, then try Map[f, step[l], {2}] –  Mr.Wizard Feb 7 '12 at 12:40
    
I need the ppost1 function as it is supposed to be used in another function that expects the signature of ppost1, i.e., an argument arg, and a context. –  asim Feb 7 '12 at 13:53
    
@asim, read my edit then –  Rojo Feb 7 '12 at 16:32
show 2 more comments

Your syntax between the two functions is different. In terms of Thread I think you mean to use:

nargList = {{1, 2}, {3, 4, 5}} // N;

nmList = {{6, 7}, {8, 9, 10}} // N;

ncontextList = {nmList, 50, 55} // N;

Thread[ppost1[nargList, Sequence @@ ncontextList]]

{ppost1[{1., 2.}, {6., 7.}, 50., 55.], ppost1[{3., 4., 5.}, {8., 9., 10.}, 50., 55.]}

But there seems to me to be another problem: your function is applied before the threading takes place. I am finding it difficult to divine your ultimate intent but I suspect this is not working the way you think it is.


Reading the question a second time you appear to be confused regarding the way Thread works. Only elements that appear at the first level of func are distributed among lists. Further, any lists over which the function is threaded must be of the same length. Please consider these examples:

Thread[func[{1, 2, 3}, {4, 5, 6}, 7]]
{func[1, 4, 7], func[2, 5, 7], func[3, 6, 7]}
Thread[func[{1, 2, 3}, {4, 5, 6}, {7}]]

During evaluation of In[2]:= Thread::tdlen: Objects of unequal length in func[{1,2,3},{4,5,6},{7}] cannot be combined. >>

Thread[func[{1, 2, 3}, {4, 5, 6, 7}]]

During evaluation of In[3]:= Thread::tdlen: Objects of unequal length in func[{1,2,3},{4,5,6,7}] cannot be combined. >>

Thread[func[{1, 2, 3}, {{4, 5, 6}, 7}]]

During evaluation of In[4]:= Thread::tdlen: Objects of unequal length in func[{1,2,3},{{4,5,6},7}] cannot be combined. >>


Finally, I believe that this is probably what you are trying to do:

(EDIT: Since you need ppost1 then I should have written:)

Block[{fc},
 Thread[ppost1[nargList, ncontextList]]
]
{{355., 460.}, {565., 670., 775.}}
share|improve this answer
    
Thanks for the above, but I need to us the compiled function via the ppost1 function. The ppost1 function will be used in another general function that needs to be called with different functions across different programs. –  asim Feb 7 '12 at 13:57
    
@asim please see the edit at the bottom of my post for an alternative to modifying fc. I am sorry that I did not understand the heart of your question sooner. –  Mr.Wizard Feb 7 '12 at 22:05
    
@Spartacus, +1 for your last edit, hehe –  Rojo Feb 7 '12 at 22:31
    
@Rojo thanks :-) –  Mr.Wizard Feb 7 '12 at 22:32
add comment

A possible solution it to use the Listable attribute of compile.

fc2 = Compile[{{arg, _Real, 1}, {c1, _Real, 
    1}, {c2, _Real}, {c3, _Real}}, c3*arg + c2*c1, 
  RuntimeAttributes -> Listable]

Then call like this:

fc2[nargList, nmList, {50, 50}, {55, 55}]

What you really want is:

(* fc2[nargList, nmList, 50, 55] *)

Unfortunately, this crashes my V8.0.4 Kernel, but it's fixed in the development version. Hope this helps.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.