Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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?

share|improve this question

3 Answers 3

up vote 2 down vote accepted

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.

share|improve this answer
    
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). –  9527 Oct 9 '13 at 21:02

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]
share|improve this answer
    
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. –  9527 Oct 9 '13 at 20:56
    
@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 :) –  Kuba Oct 9 '13 at 21:00
    
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. –  9527 Oct 9 '13 at 21:49

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}}};
share|improve this answer
    
Thanks. It works. That is the "local variable" I want. And the syntax highlighting works for me. –  9527 Oct 10 '13 at 19:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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