5
$\begingroup$

Suppose you have a cubic box containing identical particles and you want to compute the distances between each particle and every other particle in the box without double-counting (i.e., if you've computed the distance between particles 1 and 2, you don't want to repeat the computation for particles 2 and 1 when looping through 2). In C-style languages you could do something like:

for ( int i = 0; i < nparticles - 1; i++ )
{
    for ( int j = i + 1; j < nparticles; j++ )
    {
       //calculate distance and some other stuff
    }
}

In Mathematica you could do the following:

  ParallelTable[Distance[coord[[i]], coord[[j]], z], 
                            {i, 1, nparticles - 1}, {j, i + 1, nparticles}]

Where Distance is a function that takes in the positions of two particles and a boxsize variable and spits-out the distance between them. Is there a better, more elegant Mathematica-way to achieve this? I've tried using Outer to no success.

To give a specific example:

coord = {{0.336384, 0.0132788, 0.895366}, {0.531722, 
  0.703736, -0.626689}, {1.3723, 0.191368, 
  0.930669}, {1.92434, -0.561288, 0.537316}, {2.48175, 1.34384, 
  0.368834}, {1.91778, 0.489024, -0.138269}, {3.22166, 1.46687, 
  1.16486}, {3.16976, -0.134968, 1.46946}, {3.31118, 0.625944, 
  0.0811552}, {4.39825, 1.03799, 
  0.985738}, {2.68123, -0.180248, -0.110539}, {4.68779, 0.22483, 
  0.0725717}, {5.41664, 0.982811, 0.491087}, {6.43321, 0.624075, 
  0.167138}, {6.60217, 1.59568, 2.19137}, {5.48321, -0.612703, 
  1.54037}, {0.275933, 1.73027, -0.319963}, {1.16899, 
  2.62176, -0.426422}, {0.895252, 2.30479, 0.546692}, {1.32435, 
  1.46099, -0.247962}, {2.438, 1.54727, -1.84394}, {2.84289, 2.47839, 
  0.487663}, {0.947902, 2.01877, 1.65962}, {4.27311, 1.66672, 
  1.82603}, {3.51098, 1.72636, 0.209131}, {2.53455, 2.68654, 
  1.45134}, {3.79154, 1.91726, 3.06622}, {5.59738, 1.69974, 
  1.26923}, {4.74771, 2.06686, 0.627377}, {5.8998, 1.90073, 
  0.269334}, {3.76603, 2.71011, 0.018981}, {6.52431, 1.09702, 
  1.0249}, {0.514549, 4.44605, -0.926816}, {1.18538, 
  3.8988, -0.291136}, {-1.03715, 3.48421, -0.126283}, {2.15475, 
  3.24303, -0.291715}, {1.96754, 2.39311, 0.152853}, {2.28468, 
  4.21156, 0.0596945}, {1.41851, 4.21297, 1.93538}, {1.77912, 3.13171,
   0.827817}, {3.40729, 3.67042, -0.335001}, {4.14912, 4.26701, 
  0.858455}, {3.42495, 3.43054, 0.832514}, {2.65226, 0.773315, 
  1.84478}, {4.50074, 3.62477, -0.228838}, {5.67743, 
  4.08899, -1.0032}, {4.98032, 2.56005, 1.60549}, {5.21301, 
  2.61515, -0.189593}, {-0.716714, 4.48811, -0.0695819}, {0.924003, 
  5.67242, 0.689366}, {1.02188, 6.33087, 1.77669}, {0.330792, 4.2462, 
  0.228187}, {1.79568, 5.98731, -0.447117}, {1.4538, 
  4.91975, -0.371939}, {1.49597, 5.34725, 1.68155}, {1.49152, 4.62994,
   0.659604}, {4.00242, 4.6745, -0.284203}, {3.10622, 4.50629, 
  0.728059}, {3.87473, 5.84693, 1.31431}, {2.98275, 5.88126, 
  0.697273}, {4.87938, 4.86575, 0.0826803}, {6.47473, 5.84112, 
  1.05569}, {4.76077, 5.92404, 0.606916}, {6.4309, 3.70755, 
  0.813097}, {0.104133, 0.851572, 3.46545}, {0.551016, 0.780983, 
  1.69373}, {-0.594108, 2.62214, 1.8779}, {0.708406, -0.797156, 
  2.9291}, {2.0969, -0.257719, 1.69345}, {3.93626, -0.163324, 
  0.657445}, {0.781078, 1.36067, 2.66083}, {3.8494, 0.656096, 
  1.86343}, {4.30525, -0.0180448, 2.46287}, {4.80984, 0.218372, 
  1.24748}, {2.76467, -0.0677178, 2.53374}, {4.58791, -0.856503, 
  3.05766}, {5.59133, -0.108523, 0.470608}, {7.29888, 0.209516, 
  2.63152}, {5.34566, 0.991826, 4.06735}, {4.31354, 0.951664, 
  2.75418}, {0.786024, 0.835163, 0.374784}, {1.49562, 0.756177, 
  2.29413}, {-1.31348, 3.36, 2.05473}, {1.96944, 1.82599, 
  2.15945}, {1.75072, 1.30223, 1.27227}, {2.25839, 3.48229, 
  2.18914}, {0.348436, 2.50653, 2.4213}, {1.82846, 1.37269, 
  3.04588}, {3.31408, 2.12509, 2.05064}, {3.41257, 3.28132, 
  2.45043}, {2.73336, 1.98305, 2.98785}, {5.36672, 1.01905, 
  2.02999}, {4.49376, 3.19686, 0.674299}, {5.6424, 2.95267, 
  0.927283}, {4.58006, 2.97117, 2.42488}, {5.10568, 1.9436, 
  2.47794}, {0.0359706, 2.12641, 1.14963}, {0.136018, 
  3.47913, -0.546182}, {0.324015, 3.19016, 1.53741}, {-0.364055, 
  3.30565, 2.57457}, {0.639834, 3.29517, 0.505645}, {2.21284, 3.99436,
   1.14992}, {1.21456, 3.05581, 2.09513}, {2.94578, 3.94601, 
  3.25965}, {3.09293, 3.99949, 1.79511}, {4.15348, 3.53126, 
  1.64667}, {3.17003, 4.95903, 2.7816}, {3.98937, 3.99651, 
  2.56071}, {4.79954, 4.84892, 3.01249}, {5.35644, 4.06114, 
  0.728884}, {6.14876, 5.29657, 1.8754}, {3.95394, 2.44156, 
  1.21713}, {0.00856939, 6.32042, 1.89394}, {-0.435331, 7.36044, 
  2.55351}, {0.19939, 5.0767, 3.33505}, {-0.347543, 4.13423, 
  1.7466}, {0.481867, 4.5129, 1.26472}, {2.29653, 4.50625, 
  2.36835}, {0.351039, 5.00868, 2.20155}, {1.53178, 3.70154, 
  2.98418}, {2.53732, 5.04177, 1.5255}, {3.72857, 4.78197, 
  1.72687}, {3.20208, 5.71681, 2.0526}, {5.32521, 6.78749, 
  2.3629}, {5.22618, 5.09716, 1.11705}, {5.94678, 7.11508, 
  1.51961}, {4.62847, 5.63837, 1.95489}, {6.28939, 4.82977, 
  0.848559}, {0.0461207, 1.93522, 3.25444}, {0.371978, -0.0986856, 
  3.58917}, {-0.461638, 1.25587, 4.47311}, {0.584499, -0.644038, 
  4.46688}, {2.48808, -0.420693, 3.44016}, {2.41666, 0.660956, 
  3.88881}, {1.55183, -0.235559, 2.81671}, {1.59083, -0.113905, 
  4.47863}, {3.60737, 0.284417, 3.38969}, {4.14487, 1.05219, 
  3.87699}, {4.27162, 0.351588, 4.8352}, {4.79354, 0.125734, 
  3.38844}, {5.27955, 0.079976, 4.41649}, {5.41948, 0.854351, 
  3.03103}, {5.22856, 0.775168, 5.21907}, {6.37806, 0.167375, 
  4.72112}, {-1.02014, 1.96112, 3.69853}, {-0.419047, 2.83171, 
  3.46298}, {-1.31457, 2.99279, 4.20992}, {2.44419, 0.358023, 
  4.95077}, {1.49318, 2.32455, 3.03509}, {0.432945, 4.0273, 
  3.6404}, {2.43741, 2.95397, 3.21087}, {3.14394, 1.4998, 
  3.86404}, {3.25509, 0.897897, 2.71971}, {4.45936, 3.20951, 
  3.55269}, {3.9792, 2.36403, 4.23043}, {4.70902, 1.5701, 
  4.75358}, {4.67827, 2.15833, 3.48814}, {5.44659, 2.80719, 
  3.058}, {5.12916, 3.09863, 5.67653}, {7.26935, 1.50287, 
  4.25862}, {-1.81989, 4.53932, 1.82345}, {0.556698, 3.93986, 
  2.51026}, {0.995211, 4.14387, 4.78229}, {0.27128, 3.07496, 
  4.3641}, {-0.718274, 3.82941, 3.61474}, {1.34653, 3.4258, 
  4.05185}, {0.666971, 2.94969, 3.26312}, {3.41411, 2.84055, 
  3.56064}, {2.67536, 5.2721, 3.64452}, {3.40383, 5.93004, 
  3.15271}, {4.1124, 6.19419, 3.95084}, {4.08112, 4.5837, 
  4.80518}, {4.98851, 3.90126, 2.90884}, {6.04449, 4.53769, 
  2.73099}, {5.45906, 5.56679, 2.58463}, {5.09465, 4.17775, 
  3.97109}, {-0.175458, 4.9133, 4.37999}, {0.880872, 5.07276, 
  4.35447}, {-0.131287, 5.91199, 5.42513}, {1.58653, 4.74081, 
  3.71834}, {1.36079, 5.03015, 2.71108}, {2.43226, 5.70154, 
  4.58147}, {1.42105, 5.88282, 3.64901}, {2.1028, 4.374, 
  4.68369}, {2.18209, 5.72639, 2.59178}, {5.44592, 6.0964, 
  3.55996}, {3.63535, 6.13173, 5.09292}, {4.66946, 5.20011, 
  4.01056}, {6.4787, 6.02617, 2.89552}, {6.054, 6.96222, 
  3.57906}, {6.46182, 5.96925, 3.94092}, {5.69617, 5.10088, 
  3.64138}, {0.615022, -0.027696, 5.42941}, {1.26461, 0.630006, 
  3.71384}, {0.883915, 1.42777, 5.47437}, {1.6792, 0.219376, 
  5.6289}, {2.59437, -0.684772, 5.60909}, {3.38078, 0.833026, 
  5.01004}, {2.84052, 0.573809, 5.90501}, {2.52553, 0.273467, 
  7.55756}, {4.41898, 0.696667, 5.85818}, {5.60858, 0.76452, 
  6.21228}, {5.74785, -1.1999, 7.01252}, {5.21135, -0.1117, 
  5.70978}, {4.66543, -0.919731, 4.87041}, {5.88829, 2.25357, 
  4.8022}, {6.3881, 1.00455, 5.545}, {6.22542, 0.0248028, 
  6.01928}, {0.586144, 0.520938, 4.41165}, {1.2068, 2.54395, 
  4.71756}, {0.436429, 2.33501, 5.52469}, {1.97207, 1.17024, 
  5.77531}, {2.25879, 3.04413, 5.01964}, {3.16137, 2.32338, 
  5.14988}, {2.02769, 2.28359, 5.84169}, {2.83295, 1.61539, 
  5.95777}, {3.8353, 1.69209, 5.8488}, {3.96829, 4.30873, 
  3.70322}, {2.99406, 2.69444, 6.18322}, {4.51472, 1.36171, 
  6.60083}, {3.63584, 3.42738, 4.39589}, {6.12614, 2.20446, 
  5.82261}, {4.02039, 2.78657, 5.66757}, {5.06004, 1.83423, 
  5.81263}, {1.10964, 3.21626, 5.41782}, {0.855608, 5.48462, 
  5.49}, {-0.571077, 3.27243, 5.29777}, {2.72265, 4.45985, 
  5.80695}, {1.48765, 1.09592, 4.7271}, {2.57181, 3.58383, 
  4.09092}, {1.85261, 3.99701, 5.63123}, {2.39584, 2.38821, 
  4.08817}, {3.14111, 4.4719, 4.37108}, {3.24159, 5.19853, 
  5.18419}, {2.9781, 5.51286, 6.43951}, {3.5866, 3.85079, 
  5.36787}, {4.57368, 3.59342, 4.68331}, {5.97774, 4.05604, 
  4.6439}, {4.63198, 4.10956, 5.6602}, {6.58299, 2.72811, 
  6.98548}, {-0.360483, 4.87033, 5.40138}, {1.66172, 6.00282, 
  5.1889}, {0.0873425, 5.97487, 6.85352}, {-0.0873903, 5.21734, 
  6.30516}, {2.00121, 5.14253, 5.51722}, {4.29976, 5.27308, 
  5.64666}, {0.988506, 6.73676, 6.59325}, {2.25374, 5.26316, 
  7.00213}, {3.74567, 6.67823, 6.34782}, {4.79574, 5.92614, 
  6.35025}, {3.28421, 6.66997, 4.2437}, {3.88385, 5.62567, 
  6.89584}, {3.46529, 5.45601, 4.13669}, {5.23652, 4.7538, 
  4.97666}, {5.72676, 5.96949, 4.96138}, {5.58535, 5.25335, 5.92877}}

coord contains the {x, y, z} coordinates of 256 particles.

Distance[x_, y_, z_] :=  If[# < z/2, #, Sequence @@ {}] & @
                  Sqrt[Total[((x - y) - z*Round[(x - y)/z])^2]]

Distance computes the periodic distance between two particles and only returns it if it meets a criterion.

$\endgroup$
7
  • $\begingroup$ What do you consider "more elegant"? $\endgroup$
    – jVincent
    Feb 8, 2013 at 23:53
  • $\begingroup$ @jVincent, anything better than Table $\endgroup$
    – RunnyKine
    Feb 8, 2013 at 23:55
  • 1
    $\begingroup$ Why use ParallelTable? Try Compile with Table or Do loop and approriate options. The only way to be even faster is to use C or Fortran for the loop and use MathLink. Fortran rules. $\endgroup$ Feb 9, 2013 at 0:06
  • 1
    $\begingroup$ This question is a nice addition to the discussion here: Alternatives to procedural loops and iterating over lists in Mathematica $\endgroup$
    – Jens
    Feb 9, 2013 at 6:15
  • 2
    $\begingroup$ Related: (8272) $\endgroup$
    – Mr.Wizard
    Feb 9, 2013 at 7:28

3 Answers 3

13
$\begingroup$

How about this (final version with improvement suggested by jVincent):

mutualDistances[coords_,distF_] :=
    distF @@@ Subsets[coords, {2}]

?

In your case, you should use distf = Distance[##,z]& with whatever your z is. The result you get corresponds to what you'd get with your Table code, if you additionally Flatten it.

$\endgroup$
3
  • $\begingroup$ @jVincent Yes, that's true. I have a habit of working with indices,but here they don't bring much of an advantage. Will edit your suggestion in, thanks. $\endgroup$ Feb 9, 2013 at 0:27
  • $\begingroup$ This is clearly an elegant way. I'm just waiting to see other clever solutions before I accept it. Thanks for your input, I learned something new today. $\endgroup$
    – RunnyKine
    Feb 9, 2013 at 0:38
  • $\begingroup$ @RunnyKine Right, it is a good habit to not accept immediately. This would motivate others to contribute more answers. $\endgroup$ Feb 9, 2013 at 0:39
5
$\begingroup$

In cases like this, you could also use SparseArray. The equivalent of your Table command would be:

dist = SparseArray[{i_, j_} :> Distance[coord[[i]], coord[[j]], 3] /; i > j, 256];

where Distance and coord are as defined in your question, and 3 is some arbitrary value I chose for z.

You can get all the non-zero values as

dist["NonzeroValues"] 

and you'll have Null wherever Distance returned a Sequence[]. You can remove this by either defining your sequence to return 0 (in which case, you can simply use dist["NonzeroPositions"] to get the pairs for which something was returned), or via a replacement: /. Null -> Sequence[]

$\endgroup$
1
  • $\begingroup$ Another elegant solution. Thanks. $\endgroup$
    – RunnyKine
    Feb 9, 2013 at 0:47
2
$\begingroup$

I suppose subsets is what you're looking for. Similar to Leonid's answer:

Select[EuclideanDistance @@@ Subsets[coords, {2}], # < z/2 &]

Another function along these lines is Outer, which operates on the Cartesian product of two lists. (Tuples and Permutations are also useful).

$\endgroup$

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.