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$
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
    $\begingroup$ Ha! When I started to write this code I didn't expect it resulting in such a compact line! :) $\endgroup$ – Dr. belisarius Jan 14 '16 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 '18 at 3:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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