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.

How does one use Outer with a compiled function that accepts 3 or more arguments. Alternatively, how does one create a compiled function with 3 or more arguments that can be used with Outer?

I am trying to use the following function:

minimumImagePD =  Compile[{{x, _Real, 1}, {y, _Real, 1}, {z, _Real}}, 
                 Total[( (x - y) - z * Round [ (x - y) / z]) ^ 2]]

This function compiles just fine but you can't use it with Outer. Trying the following doesn't work because Compile does not "see" the argument 'z':

minimumImagePD2[z_Real] =  Compile[{{x, _Real, 1}, {y, _Real, 1}}, 
                 Total[((x - y) - z * Round[ (x - y)/z] ) ^ 2]]

    Outer[minimumImagePD2[3.2], {{2.1, 3.2, 4.3}}, {{3.2, 4.3, 2.8}, 
                           {1.1, 2.2, 3.3},   {3.4, 2.0, 6.5}}, 1].

Now, If I replace z in minimumImagePD with a number as follows:

minimumImagePD3 =  Compile[{{x, _Real, 1}, {y, _Real, 1}}, 
  Total[((x - y) - 3.25026*Round[(x - y)/3.25026])^2]]

The function compiles and works fine as with the following example:

Outer[minimumImagePD3, {{2.3, 4.3, 6.5}}, {{2.1, 4.8, 7.3}, {2.2, 
   1.1, 4.3}, {2.1, 3.3, 4.7}}, 1] // Flatten

Which gives:

{0.93, 1.11557, 3.14325}

As noted by Oleksandr R. below, using set-delayed in minimumImagePD2 solves the problem.

share|improve this question
    
The problem is not the number of arguments. It is that Total doesn't accept a sequence as argument. The solution : minimumImagePD = Compile[{{x, _Real, 1}, {y, _Real, 1}, {z, _Real}}, Total[List @ ((x - y) - z*Round[(x - y)/z])^2]] –  andre Feb 7 '13 at 18:03
    
@andre, actually the result of the calculation is NOT a sequence it's a list, as both x and y are Lists (Hence the 1 in {x, _Real, 1} etc. The function works fine If I replace z with a number instead. So the problem is with Outer as there's no room for that third argument. –  RunnyKine Feb 7 '13 at 18:17
    
must go outside. I See that in 2 hours. Sorry –  andre Feb 7 '13 at 18:21
    
@RunnyKine: Could you give an example call to Outer with the minimumImagePD? –  Joel Klein Feb 7 '13 at 18:24
    
@Joel Klein, that's exactly the reason I asked this question. There's no place for the third argument z to go. That's why I tried the 2nd variation of the function. minimumImagePD should accept List just like I showed with minimumImagePD2. –  RunnyKine Feb 7 '13 at 18:28
show 7 more comments

3 Answers 3

up vote 3 down vote accepted

The original definition of minimumImagePD can be used with Outer with this syntax:

Outer[minimumImagePD[##, zvalue] &, xlist, ylist, 1]

Outer provides two arguments to the pure function minimumImagePD[##, zvalue] &, and the pure function inserts those two arguments into the ## (SlotSequence), so that minimumImagePD is called with the expected three arguments in total.

share|improve this answer
    
This is exactly what I wanted. So elegant. Thanks –  RunnyKine Feb 7 '13 at 21:24
add comment

I am not sure I understand 100% what you are looking for but does this help:

This inserts the value into the compiled function:

minimumImagePD2[zIn_Real] := 
  With[{z = zIn},
   Compile[{{x, _Real, 1}, {y, _Real, 1}}, 
    Total[((x - y) - z*Round[(x - y)/z])^2]]]

f = minimumImagePD2[3.25026]

The use as before.

Outer[f, {{2.3, 4.3, 6.5}}, {{2.1, 4.8, 7.3}, {2.2, 1.1, 4.3}, {2.1, 3.3, 4.7}}, 1]
(* {{0.93, 1.11557, 3.14325}} *)

As suggested by OleksandrR, the With is not strictly necessary, so you can also go with

minimumImagePD2[z_Real] := 
   Compile[{{x, _Real, 1}, {y, _Real, 1}}, 
    Total[((x - y) - z*Round[(x - y)/z])^2]]]

I find the With solution clearer, but clearly that is a matter of taste.

share|improve this answer
    
this has been suggested above by Oleksandr R. It's just adding set-delayed to my minimumImagePD2 function. –  RunnyKine Feb 7 '13 at 19:49
    
I am doing something somewhat different here; I generate the compiled function with the proper value inside and then use it as often as I want. Also this presetting allows for optimizations in compile –  user21 Feb 7 '13 at 19:59
    
@OleksandrR., I'd leave it in; it's more general for other type of problems. –  user21 Feb 7 '13 at 20:01
add comment

Here is a more elegant way, I think, to solve this problem. By including the third argument as one of the Lists in Outer.

minimumImagePD = Compile[{{x, _Real, 1}, {y, _Real, 1}, {z, _Real}}, 
  Total[((x - y) - z * Round[ (x - y) / z] )^2]]

And using it like this:

Outer[minimumImagePD, {{2.3, 4.3, 6.5}}, {{2.1, 4.8, 7.3}, {2.3, 1.1, 
    4.3}, {2.1, 3.3, 4.7}}, {3.25026}, 1] // Flatten
share|improve this answer
    
This is also how I would do it. +1 –  Mr.Wizard Mar 8 '13 at 2:40
    
@Mr.Wizard, thanks. –  RunnyKine Mar 8 '13 at 3:33
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.