2
$\begingroup$

The problem:
I want to define a function tab to replace the long line

Table[f[i,j,k,l],{i,3},{j,3},{k,3},{l,3}]

by a shorter line

tab[f[i,j,k,l],i,j,k,l]

Then I need to declare i,j,k,l in tab to be local variables, just like in Table.

My trial:

tab[f_, jlist__] := Module[{jlist2 = {jlist}, jlist3}, 
 jlist3 = Sequence @@ ({#1, 3} & ) /@ jlist2; 
  Table[f, Evaluate[jlist3]]]

Then I succeeded in

(*Input := *) tab[h[i, j], i, j]
(*Output:=  {{h[1, 1], h[1, 2], h[1, 3]}, {h[2, 1], h[2, 2], h[2, 3]},  {h[3, 1], h[3, 2], h[3, 3]}}*)    

whose output is the same as from Table[h[i,j],{i,3},{j,3}]. But I failed in

(*Input := *) tab[(f[i, j] = g[i, j]), i, j]
(* {{g[1, 1], g[1, 2], g[1, 3]}, {g[2, 1], g[2, 2], g[2, 3]}, {g[3, 1], g[3, 2], g[3, 3]}} *)

in which f[i,j]=g[i,j] is evaluated first. I wanted it to behave as Table[f[i,j]=g[i,j],{i,3},{j,3}].


Update: Below rcollyer's answer leads to the correct output by using SetAttributes[tab,HoldAll] first. However, I still want to know if I can declare i and j as local variables. So far they are not local variables and I would have errors like:

(*Input :=*) i=3; tab[f[i],i]
(* Error message "Table::itraw: Raw object 3 cannot be used as an iterator. >>"
  Output:= Table[f[i], {3, {0, 1, 2, 3}}] *)

Can anyone solve this?

$\endgroup$

3 Answers 3

3
$\begingroup$

You are looking for the attribute HoldAll, or HoldFirst:

ClearAll[tab];
SetAttributes[tab, HoldAll];
tab[f_, jlist__] := 
 Module[{jlist2 = {jlist}, jlist3}, 
  jlist3 = Sequence @@ ({#1, 3} & ) /@ jlist2; 
  Table[f, Evaluate[jlist3]]
 ]

tab[(f[i, j] = g[i, j]), i, j]
(*
{{g[1, 1], g[1, 2], g[1, 3]}, 
 {g[2, 1], g[2, 2], g[2, 3]}, 
 {g[3, 1], g[3, 2], g[3, 3]}}
*)

Note, to clear everything from the definition of tab, you will need to use ClearAll, as Clear does not cover Attributes.

$\endgroup$
1
  • 1
    $\begingroup$ Thanks. This is what I want. I still wonder if we can make i and j in tab[f[i,j],i,j] local variables? Just like in Table[f[i,j],{i,3},{j,3}] the variables i and j are made special as local variables, and these variables appear in blue color (in ver9.0.4). $\endgroup$
    – 9527
    Oct 9, 2013 at 21:02
2
$\begingroup$

Isn't this function built-in and called Array?

Array[f, {2, 2}]
{{f[1, 1], f[1, 2]}, {f[2, 1], f[2, 2]}}
Array[(f[##] = g[##]) &, {2, 2}]
{{g[1, 1], g[1, 2]}, {g[2, 1], g[2, 2]}}
?? f
f[1,1]=g[1,1]
f[1,2]=g[1,2]
f[2,1]=g[2,1]
f[2,2]=g[2,2]
$\endgroup$
3
  • $\begingroup$ Array is good to get a tensor in a compact way. But it is not good to keep tracking the indices of tensors in computation. For example, if I want to compute $C^{ijk}_{p}=\sum_{lmn}A^{ijk}_{lmn}B^{lmn}_{p}$, with all indices running over the same range, then mySum[A[i,j,k][l,m,n]B[l,m,n][p],l,m,n] would be more convenient then Array. $\endgroup$
    – 9527
    Oct 9, 2013 at 20:56
  • $\begingroup$ @9527 You can keep track of the indices with #, #2, #3 corresponding to the dimmensions of an array. I think so, I'm not sure, I have not got much experience with multi indices tensors operations :) $\endgroup$
    – Kuba
    Oct 9, 2013 at 21:00
  • $\begingroup$ yes, you are right. For $C^{ijk}_{p}=\sum_{lmn}A^{ijk}_{lmn}B^{lmn}_{p}$, I can use tensorC=TensorContract[tensorA,TensorB,{{4,1},{5,2},{6,3}}], which is efficient and compact. But we need to figure out the pairs {{4,1},{5,2},{6,3}} correctly first. It would be still good to keep tracking the indices by writing them down explicitly in many cases though. $\endgroup$
    – 9527
    Oct 9, 2013 at 21:49
1
$\begingroup$

Local variables in Mathematica come in some variants so you'd actually have to specify what kind of local variables you want to create (see other questions about Block, Module and With for details, note that all of them have their peculiarities). As far as I understand, you just want to ensure that global definitions don't cause errors with your tab definition, for that it is sufficient to ensure that nothing is evaluated too early and let Table do the localization. Here is one way to achieve that:

ClearAll[tab];
SetAttributes[tab, HoldAll];
tab[body_, varnames__] := Module[{iter = Replace[Hold[varnames], v_ :> {v, 3}, {1}]},
  Table @@ Join[Hold[body],iter]
]

you can try what happens without applying Table to see how this works.

As for the syntax highlighting you would need to define a corresponding SyntaxInformation for tab. Here is something that seems to work, but honestly I'm not sure whether there is something better than the "Integrate"-type I used, the usual candidates for local variables need iterator like lists for the highlighting to work. Maybe you'll find more information about writing a better SyntaxInformation elsewhere:

SyntaxInformation[tab] = {"ArgumentsPattern" -> {_, __}, 
  "LocalVariables" -> {"Integrate", {2,Infinity}}};
$\endgroup$
1
  • $\begingroup$ Thanks. It works. That is the "local variable" I want. And the syntax highlighting works for me. $\endgroup$
    – 9527
    Oct 10, 2013 at 19:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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