2

I've seen similar posts to this, but not with as many variables. I need to loop over 8 variables, with only two values each(1 and 2), so I can loop over the 16 possible input and output states, and write the symbolic results in a 16x16 matrix. Instead of just nesting 8 for loops, is there a more readable way?

Edit: I'm sorry I didn't include the code needed to actually help me, this is my first time posting here. The goal is to evaluate the function

takeOpVal[O1_, O2_, O_ 3, O_ 4, O_ 5, O_ 6, O_ 7, O_ 8, U_] := Tr[KroneckerProduct[O1, O2, O3, O4] . U . KroneckerProduct[O5, O6, O7, O8] . ConjugateTranspose[U]];

for each combination of the 2x2 Identity matrix and Pauli Z matrix. I figured it would be easiest to create a "translator":

Translator = {Id, Sz}

and then simply call the function takeOpVal with Translator{i},Translator{j} etc and iterate over the variables.

thorimur
  • 9,010
  • 18
  • 32
  • 3
    Welcome to the Mathematica Stack Exchange. Could you please reduce your problem to two or three variables with two values each and show what the desired output matrix would look like? This will make the question more concrete and extensible to the eight variable case. Thanks. – Syed Jun 09 '22 at 07:46
  • 2
    Welcome! In general, you shouldn't use For loops in mathematica, especially when building tables! See Avoiding For Loops. (Its parent post is always useful too!) It's often better to use Table or Array. Table can use multiple loops, e.g. t = Table[f[i,j,k,l,m,n,o,p], {i,2}, {j,2}, {k,2}, {l,2}, {m,2}, {n,2}, {o,2}, {p,2}]. Then to get a 16x16 array, you can use ArrayReshape[t, {16, 16}], or Flatten if you need more control over which layer winds up where. – thorimur Jun 09 '22 at 08:00
  • 5
    However, a more concise way is to use Tuples, then reshape: Tuples[{1, 2}, 8] will produce a list of all possible combinations, then (if your function takes in 8 arguments) you can apply a function to each of these using f @@@ Tuples[{1, 2}, 8] (see the docs for Apply). If your function takes in a list of 8 values, use Map instead, e.g. f /@ Tuples[{1,2}, 8]. Then use ArrayReshape as before on the result. – thorimur Jun 09 '22 at 08:03
  • 2
    Also, it's good practice on this forum to provide the code you're working with so that people can copy-paste to see what works! :) – thorimur Jun 09 '22 at 08:06
  • @thorimur sorry for missing too much of the information, I have edited the post and include it now, thanks! – Lion Frangoulis Jun 09 '22 at 09:30
  • Sorry, if I'm the only one still confused, but can you please provide some explicit examples? 8 variables each with two possible values gives 256 possible inputs, not 16. How can you loop over "output states"? Isn't it the goal of a function to compute outputs? How can you loop oversomething you don't have yet? KroneckerProduct can work on arrays and matrices--what dimensions will your inputs have? You mention "2x2 identity matrix", is that what the inputs are? – lericr Jun 09 '22 at 17:45
  • I would suggest you start with the simplest possible concrete example of what your desired function would do (e.g. such-and-such input should generate such-and-such output). Then increase the scale by the smallest possible increment and show us such slightly larger concrete example. Hopefully that will show us how you want to generalize, but some commentary around what you're struggling with to get that generalization would also help. – lericr Jun 09 '22 at 17:46
  • By "what your desired function would do" I don't mean an explanation of takeOpVal--I'm assuming that it is working as you desire. I'm referring to a function to generate the inputs that takeOpVal will be applied to. (Unless I've misunderstood that as well, and you are actually trying to get takeOpVal to work.) – lericr Jun 09 '22 at 17:49

1 Answers1

1

(I'm repeating some things I said in a comment just for the sake of completeness :) )

Welcome! In general, you shouldn't use For loops in mathematica, especially when building tables! See Avoiding For Loops. (Its parent post is always useful too!)

It's often better to use Table or Array to generate arrays. Table can use multiple loops, e.g.

t = Table[f[i,j,k,l,m,n,o,p], {i,2}, {j,2}, {k,2}, {l,2}, {m,2}, {n,2}, {o,2}, {p,2}]

Then to get a 16x16 array, you can use ArrayReshape[t, {16, 16}], or Flatten if you need more control over which layer winds up where. (If you're new to Mathematica, note that Mathematica has generally great documentation, which can be accessed by clicking Help at the top-right of the notebook window; lots of further info on e.g. how to use Flatten in different ways can be found there.)

However, a more concise way is to use Tuples, then reshape: Tuples[{1, 2}, 8] will produce a list of all possible combinations, then (if your function takes in 8 arguments) you can apply a function to each of these using f @@@ Tuples[{1, 2}, 8] (see the docs for Apply). f @@@ {{a,b,c}, {d,e,g}} replaces the inner List with your function, and will evaluate to {f[a,b,c], f[d,e,g],}. (Contrast with Map (/@) which prefixes f to the list itself: f /@ {{a,b,c}, {d,e,g}} evaluates to {f[{a,b,c}], f[{d,e,g}]}.)

The definition you included was for takeOpVal[O1_, O2_, O3_, O4_, O5_, O6_, O7_, O8_, U_]. (Note: the code you included had errors, e.g. O_ 3 instead of O3_. Make sure these errors aren't present in your actual code!) Seeing as you want to sort of "parametrize" this by U, I recommed using the following pattern:

takeOpVal[U_][O1_, O2_, O3_, O4_, O5_, O6_, O7_, O8_] := (* ... *)

This behaves the same way in the end, but is more convenient: we can construct takeOpVal[U] which then behaves like a function that we can apply to sequences of the 8 O arguments. (If you're familiar, this is Mathematica's built-in version of currying.)

Note that Tuples works with any list! Tuples[{Bigthing1, Bigthing2, ...}, 8] will generate all 8-tuples with elements drawn from the list given as a first argument! So we can just use your Translator list.

(Note: if you're coming from another language, you may be used to using list{i} for part access as I noticed you did in the post! Remember that here, you use double square brackets: list[[i]]. See the docs for Part for more.)

So, to put it all together:

takeOpVal[U_][O1_, O2_, O3_, O4_, O5_, O6_, O7_, O8_] := Tr[KroneckerProduct[O1, O2, O3, O4] . U . KroneckerProduct[O5, O6, O7, O8] . ConjugateTranspose[U]]

Id = IdentityMatrix[2]; Sz = PauliMatrix[3]; Translator = {Id, Sz}; (* U = YourMatrixHere *)

vals = takeOpVal[U] @@@ Tuples[Translator, 8];

ArrayReshape[vals, {16,16}]

There may be technicalities for making this line up with KroneckerProduct, though. I'm not sure exactly how you want it reshaped. If you'd like to provide more detail, I'd be happy to help further. :)

thorimur
  • 9,010
  • 18
  • 32
  • Thank you so much for the help, with your reply I got it to work! As you said, I'm coming from a different language and started learning Mathematica only a couple days ago, so things like the currying will take some time to understaand, but Ill get there.

    Thanks again for all the time you took to reply in such detail!

    – Lion Frangoulis Jun 12 '22 at 07:41