Skip to main content
added 1595 characters in body
Source Link
lericr
  • 34.1k
  • 2
  • 22
  • 78

TestingI came up with this by interpreting your question as follows. The pattern seems to take 1, 2, and 3 "columns" of the matrix {U1, U2} in turn. It appears that we have 2 terms from the 1-column case, 4 terms from the 2-column case, and 8 terms from the 3 column case. Further inspection of your example suggests that for the n-column case we have a "template" list of indexes of length n, something like {x[[1]], x[[2]], x[[3]]} in the 3-column case, where we can then replace each x with either U1 or U2. There are 2^n ways to choose the replacements, which matches our observation above.

So, at the heart we have Tuples[{1, 2}, slotCount]. The 1 and 2 represent our choices (choose from U1 or from U2), and slotCount is how many columns we want to cover. A tuple like {1, 2, 1} means "in the first slot, choose from U1, in the second from U2, and in the third from U1. Of course, we want to generalize, so U1 and U2 really mean "the first and second inputs".

Now, I want to map a "chooser" over each tuple. The chooser will index into the input lists. If I bundle my inputs like inputs = {first, second}, then the tuple {1, 2, 1} means {inputs[[1]][[1]], inputs[[2]][[2]], inputs[[1]][[3]]}, which means I need to keep track of where in the tuple I am as I map the chooser over it. That suggests using MapIndexed: MapIndexed[Part[{first, second}, ##] &][{1, 2, 1}]. We need to compose this basic chooser function with Times since that's how you wanted to transform each tuple-choice, and we need to map this whole thing over all the tuples.

Testing it on the 1-slot case:

Testing in on the 1-slot case:

I came up with this by interpreting your question as follows. The pattern seems to take 1, 2, and 3 "columns" of the matrix {U1, U2} in turn. It appears that we have 2 terms from the 1-column case, 4 terms from the 2-column case, and 8 terms from the 3 column case. Further inspection of your example suggests that for the n-column case we have a "template" list of indexes of length n, something like {x[[1]], x[[2]], x[[3]]} in the 3-column case, where we can then replace each x with either U1 or U2. There are 2^n ways to choose the replacements, which matches our observation above.

So, at the heart we have Tuples[{1, 2}, slotCount]. The 1 and 2 represent our choices (choose from U1 or from U2), and slotCount is how many columns we want to cover. A tuple like {1, 2, 1} means "in the first slot, choose from U1, in the second from U2, and in the third from U1. Of course, we want to generalize, so U1 and U2 really mean "the first and second inputs".

Now, I want to map a "chooser" over each tuple. The chooser will index into the input lists. If I bundle my inputs like inputs = {first, second}, then the tuple {1, 2, 1} means {inputs[[1]][[1]], inputs[[2]][[2]], inputs[[1]][[3]]}, which means I need to keep track of where in the tuple I am as I map the chooser over it. That suggests using MapIndexed: MapIndexed[Part[{first, second}, ##] &][{1, 2, 1}]. We need to compose this basic chooser function with Times since that's how you wanted to transform each tuple-choice, and we need to map this whole thing over all the tuples.

Testing it on the 1-slot case:

Source Link
lericr
  • 34.1k
  • 2
  • 22
  • 78

I'm going to bundle this into a function that you can use multiple times and then get your final result by aggregation.

IndexedBinaryChoice[listA_, listB_, slotCount_Integer] :=
  Map[
    Apply[Times]@*Flatten@*MapIndexed[Part[{listA, listB}, ##] &],
    Tuples[{1, 2}, slotCount]] /;
  Length[listA] == Length[listB]

Testing in on the 1-slot case:

IndexedBinaryChoice[U1, U2, 1]
(* {u10, u20} *)

2-slot case:

IndexedBinaryChoice[U1, U2, 2]
(* {u10 u11, u10 u21, u11 u20, u20 u21} *)

3-slot case:

IndexedBinaryChoice[U1, U2, 3]
(* {u10 u11 u12, u10 u11 u22, u10 u12 u21, u10 u21 u22, u11 u12 u20, u11 u20 u22, u12 u20 u21, u20 u21 u22} *)

Now, let's just refine our definition of IndexedBinaryChoice by adding this:

IndexedBinaryChoice[listA_, listB_] :=
  Flatten[IndexedBinaryChoice[listA, listB, #] & /@ Range[Length@listA]] /; 
  Length[listA] == Length[listB]

And now,

IndexedBinaryChoice[U1, U2]
(* This should be equal to UU *)

You might want to add other validity checks.