8
$\begingroup$

I am finding myself having to code functions like this:

$$\text{answer} = \sum_{k_0 = 0}^{\color{Blue}n_0} \sum_{k_1=0}^{\color{Blue}n_1}\cdots\sum_{k_{N-1}=0}^{\color{Blue}n_{N-1}} \frac{P_{k_0,k_1,\ldots,k_{N-1}}(\color{Red}X_0 \delta_{k_0,\color{Blue}n_0}, \color{Red}X_1 \delta_{k_1,\color{Blue}n_1},\cdots,\color{Red}X_{N-1}\delta_{k_{N-1},\color{Blue}n_{N-1}})}{\color{Red}X_0^{\color{Blue}n_0-k_0}\color{Red}X_1^{\color{Blue}n_1-k_1}\cdots \color{Red}X_{N-1}^{\color{Blue}n_{N-1}-k_{N-1}}}\,.$$

The user inputs two lists of equal length $N$:

  1. a List of symbols $\color{Red}X_j$ (listX), and
  2. a List of integers $\color{Blue}n_j$ (listInt) $\enspace j = 0,1,\ldots,N-1$

So, an input would be for example:

listInt = {3, 2, 2};   (*list of non-negative integers*)
listX = {a, b, c};     (*list of the X's*)

Now, my awful implementation of the function:

With[
  {
   indicesForP = Table[k[i], {i, 0, Length[listInt] - 1}], 
   argumentsForP = Table[If[listInt[[i + 1]] - k[i] == 0, Evaluate[listX[[i + 1]]], 0], {i, 0, Length[listInt] - 1}], 
   denomList = Table[{Evaluate[listX[[i + 1]]], listInt[[i + 1]] - k[i]}, {i, 0, Length[listInt] - 1}], 
   iteratorList = Sequence @@ Table[{k[i], 0, listInt[[i + 1]]}, {i, Length[listInt] - 1, 0, -1}]
  },

   (*BIF = Big Internal Function*)
   Sum[   BIF[P[indicesForP][argumentsForP], denomList],   iteratorList]
]

(For completeness, BIF is an internal function that processes each fraction in the multi-sum, and the syntax is basically: BIF[numerator, denominatorList])

Problem: For every "$\cdots$" I have to construct a list/sequence of iterators, or a list of arguments (or list of whatever) inside With and then inject it. In this particular (simple) example, there are 4 x "$\cdots$", so I had to inject 4 different things just to make one line of code. I have to write programs involving several lines of code that have many more "$\cdots$"'s, and my With has so many localized variables, my program looks like a total kludge. Is there a more efficient way to construct lines of code with variable number of lists/sequences of things?

$\endgroup$

1 Answer 1

19
+50
$\begingroup$

The trick is thinking about list structural operations, not indexes like you would do in common procedural languages.

The following does the same as your code, but is terser and easier to follow

lint = {3, 2, 2};
lx   = {a, b, c};
idx  = Tuples[Range[0, #] & /@ lint];

dd = BIF[p[#][lx (1 - Unitize[lint - #])], Transpose@{lx, lint - #}] & /@ idx // Tr
$\endgroup$
2
  • 2
    $\begingroup$ Ha! When I started to write this code I didn't expect it resulting in such a compact line! :) $\endgroup$ Jan 14, 2016 at 1:41
  • $\begingroup$ Hi! I managed to simplify your answer so that it doesn't need Tuples. Here it is: Array[BIF[p[{##}][lx (1 - Unitize[lint - {##}])], Transpose@{lx, lint - {##}}] &, lint + 1, ConstantArray[0, Length[lint]], Plus]. A tad faster according to RepeatedTiming. $\endgroup$
    – QuantumDot
    Jul 11, 2018 at 3:49

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.