The strange variable return form of Module

See my following exmaple:

gensBCSIdentifyGroup[gens_List]:=Module[{x,y,z},
Table[(i[[1;;3,1;;3]] . Transpose[{{x,y,z}}] +i[[1;;3,4]])//Transpose,{i,gens}]//ArrayFlatten[#,1]&//ToString[#,InputForm]&//StringReplace[#,{"("->"",")"->""}]&
]

In[341]:= SGGenSetAK227Left2
%//gensBCSIdentifyGroup

Out[341]= {{{-1, 0, 0, 1/4}, {0, 0, -1, 1/4}, {1, 1, 1, 1/4}, {0, 0, 
   0, 1}}, {{0, 1, 0, 0}, {0, 0, 1, 0}, {-1, -1, -1, 0}, {0, 0, 0, 1}}}

Out[342]= "{{1/4 - x$206730, 1/4 - z$206730, 1/4 + x$206730 + \
y$206730 + z$206730}, {y$206730, z$206730, -x$206730 - y$206730 - \
z$206730}}"

In fact, I want to obtain the following result:

In[379]:= SGGenSetAK227Left2
%//gensBCSIdentifyGroup

Out[379]= {{{-1, 0, 0, 1/4}, {0, 0, -1, 1/4}, {1, 1, 1, 1/4}, {0, 0, 
   0, 1}}, {{0, 1, 0, 0}, {0, 0, 1, 0}, {-1, -1, -1, 0}, {0, 0, 0, 1}}}

Out[380]= "{{1/4 - x, 1/4 - z, 1/4 + x + y + z}, {y, z, -x - y - z}}"

Any hints for fixing this problem?

Regards,
Zhao

Many hints here:

Zhao, I would suggest that you try thinking “in the small” before thinking “in the large”. Looking at your code makes me think you spent a lot of time wrestling with the structures on the large scale–a Transpose here, an ArrayFlatten there, and so on. Sometimes it’s much simpler and clearer (and more maintainable) to first figure out how to do the small and easy things, and then compose/augment them to handle the larger more complex things. For example, at the small scale what you’re trying to do is something like this:

{-1, 0, 0, 1/4} . {x, y, z, 1}

This could be turned into a function that operates on a 4-element list:

Dot[#, {x, y, z, 1}] &

You could also name this function, but I don’t know a good name, and all I want to do at this point is demonstrate how to use this “small” function as part of a larger process.

The data you’ve stored in the variable SGGenSetAK227Left2 is just a bunch of 4-element lists arranged into a larger structure. This suggests that you can just map the “small” function over this larger structure:

Map[Dot[#, {x, y, z, 1}] &, SGGenSetAK227Left2, {-2}]
(* {{1/4 - x, 1/4 - z, 1/4 + x + y + z, 1}, {y, z, -x - y - z, 1}} *)

But it looks like you want to ignore the last “column”. Instead of trying to work that into the process, just adjust your data structure first:

Map[Dot[#, {x, y, z, 1}] &, SGGenSetAK227Left2[[All, 1 ;; 3]], {-2}]
(* {{1/4 - x, 1/4 - z, 1/4 + x + y + z}, {y, z, -x - y - z}} *)

And finally, you want the result as a string.

Map[Dot[#, {x, y, z, 1}] &, SGGenSetAK227Left2[[All, 1 ;; 3]], {-2}] // InputForm // ToString

And just a tangential comment… Having seen several of your posts now, your “go to” strategy seems to always be “put everything in a Module”. You seem to like to set up a sort of “block” in which to do a bunch of sequential processing steps. This style is often called “imperative”. Without debating the pros and cons of that style, I’ll just say that Mathematica gives you many very powerful alternatives to that style. To get the most out of Mathematica, I would encourage you eschew Module for awhile, and look for alternative approaches. Maybe you don’t really care about what style you’re using and just want to get working code, and that’s fine, but you will be forever wrestling with the language instead of learning to use it effectively.

Using Block instead of Module

Function:

f[gens_List]:=Block[
  {x,y,z},
  Table[
    (i[[1;;3,1;;3]] . Transpose[{{x,y,z}}]+i[[1;;3,4]])//Transpose,{i,gens}
  ]
  //ArrayFlatten[#,1]
]

Input:

mIn = {{{-1, 0, 0, 1/4}, {0, 0, -1, 1/4}, {1, 1, 1, 1/4}, {0, 0, 0, 
     1}}, {{0, 1, 0, 0}, {0, 0, 1, 0}, {-1, -1, -1, 0}, {0, 0, 0, 
     1}}};

Output:

In[3]:= f[mIn]
Out[3]= {{1/4 - x, 1/4 - z, 1/4 + x + y + z}, {y, z, -x - y - z}}

Hi Hans,

Thank you for your tip. It works.

But there is a missing & in your code, which should be written as follows:

f[gens_List]:=Block[
  {x,y,z},
  Table[
    (i[[1;;3,1;;3]] . Transpose[{{x,y,z}}]+i[[1;;3,4]])//Transpose,{i,gens}
  ]
  //ArrayFlatten[#,1]&
]

Hi Eric,

Based on your advice, I tried the following methods, and they all worked:

In[1386]:= finalaffops

Method 1:

Table[(i[[1;;3,1;;3]] . Transpose[{{x,y,z}}] + i[[1;;3,4]])//Transpose,{i,finalaffops}]//ArrayFlatten[#,1]&

Method 2:

Plus@@{ArrayFlatten[#[[1;;3,1;;3]] . Transpose[{{x,y,z}}],1],#[[1;;3,4]]}&/@finalaffops

Method 3:

Join[finalaffops,{{{1,0,0,1/2},{0,1,0,1/2},{0,0,1,1/2},{0,0,0,1}}}];
Map[Dot[#, {x, y, z, 1}] &, %[[All, 1 ;; 3]], {-2}]
Out[1386]= {{{0, -1, 0, 1/2}, {0, 0, -1, 1/2}, {-1, 0, 0, -(1/2)}, {0,
    0, 0, 1}}, {{0, 1, 0, -1}, {-1, 0, 0, 1}, {0, 0, -1, -2}, {0, 0, 
   0, 1}}}

Out[1387]= {{1/2 - y, 1/2 - z, -(1/2) - x}, {-1 + y, 1 - x, -2 - z}}

Out[1388]= {{1/2 - y, 1/2 - z, -(1/2) - x}, {-1 + y, 1 - x, -2 - z}}

Out[1390]= {{1/2 - y, 1/2 - z, -(1/2) - x}, {-1 + y, 
  1 - x, -2 - z}, {1/2 + x, 1/2 + y, 1/2 + z}}

P.S.: Your code snippet is the most concise one in all these methods.

Well, then there’s been some misunderstanding, because the code I posted reproduces your expected output exactly. In your new examples you’ve introduced finalaffops but haven’t shown how it’s defined. Inferring from the output you show, I get this:

test = {{{0, -1, 0, 1/2}, {0, 0, -1, 1/2}, {-1, 0, 0, -(1/2)}, {0, 0, 
    0, 1}}, {{0, 1, 0, -1}, {-1, 0, 0, 1}, {0, 0, -1, -2}, {0, 0, 0, 
    1}}};
Map[Dot[#, {x, y, z, 1}] &, test[[All, 1 ;; 3]], {-2}] ==
 ArrayFlatten[
  Transpose /@ (Map[Dot[#, Transpose[{{x, y, z, 1}}]] &, 
     test[[All, 1 ;; 3]], {-2}]), 1]
(*True*)

So, I don’t know what to tell you.

Yes. You’re right. Your philosophy of trying to think “in the small” before thinking “in the large” is a wonderful, even great trick!

More importantly, based on this method, many concise solutions can be found, and the logical correctness can be guaranteed from the atomic level.