1
$\begingroup$

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.

$\endgroup$
12
  • $\begingroup$ 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]] $\endgroup$
    – andre314
    Feb 7, 2013 at 18:03
  • $\begingroup$ @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. $\endgroup$
    – RunnyKine
    Feb 7, 2013 at 18:17
  • $\begingroup$ must go outside. I See that in 2 hours. Sorry $\endgroup$
    – andre314
    Feb 7, 2013 at 18:21
  • $\begingroup$ @RunnyKine: Could you give an example call to Outer with the minimumImagePD? $\endgroup$
    – Joel Klein
    Feb 7, 2013 at 18:24
  • $\begingroup$ @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. $\endgroup$
    – RunnyKine
    Feb 7, 2013 at 18:28

3 Answers 3

3
$\begingroup$

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.

$\endgroup$
1
  • $\begingroup$ This is exactly what I wanted. So elegant. Thanks $\endgroup$
    – RunnyKine
    Feb 7, 2013 at 21:24
3
$\begingroup$

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.

$\endgroup$
3
  • $\begingroup$ this has been suggested above by Oleksandr R. It's just adding set-delayed to my minimumImagePD2 function. $\endgroup$
    – RunnyKine
    Feb 7, 2013 at 19:49
  • $\begingroup$ 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 $\endgroup$
    – user21
    Feb 7, 2013 at 19:59
  • $\begingroup$ @OleksandrR., I'd leave it in; it's more general for other type of problems. $\endgroup$
    – user21
    Feb 7, 2013 at 20:01
2
$\begingroup$

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
$\endgroup$
2
  • $\begingroup$ This is also how I would do it. +1 $\endgroup$
    – Mr.Wizard
    Mar 8, 2013 at 2:40
  • $\begingroup$ @Mr.Wizard, thanks. $\endgroup$
    – RunnyKine
    Mar 8, 2013 at 3:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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