What are the requirements for well behaved variables?
Functions are not variables, although in most cases, the kernel treats undefined variables and functions identically. Sometimes it doesn't. After all, there are places in mathematics where the difference between a number and a function is important.
One extreme and undocumented example is Dt[]
, the total derivative function. There,f[1]
is very much different from f1
. f[1]
is a number, the value of f
at 1, constant by definition of a mathematical function of one variable, while f1
is not assumed to be constant unless an explicit declaration is made.
f[1] f[1]
Head[f[1]] f
AtomQ[f[1]] False
Dt[f[x], x] f'[x]
Dt[f[y], x] Dt[y, x] f'[y]
Dt[f[1], x] 0
Dt[f1, x] Dt[f1, x]
D[f[1], x] 0
What is the recommended and most elegant form of indexed variables?
A very simple method is to make this definition for each indexed variable:
x[i_Integer] := x[i] = With[{u = Unique[x]}, Format[u] = Subscript[x, i]; u]
Or,
defineIndexedVariable[x_Symbol] := (
x[i_Integer] := x[i] = With[{u = Unique[x]}, Format[u] = Subscript[x, i]; u]
)
It allows negative subscripts, doesn't use Symbol
, and Unique[x]
handles Context
properly, but InputForm[Array[x,5]]
prints (say) {x$2136, x$2152, x$2163, x$2164, x$2165}
. There is no temptation to sometimes write x[1]
and sometimes write x$2136
.
Another more complicated method of constructing symbols on the fly is well, not very elegant, and is an example of how complicated things can suddenly collapse into simplicity, but it does avoid repeated string operations and problems with $Context
. It allows us to write v[1]
and have it print as Subscript[v, 1]
(which displays $\text{v}_1$), and have {InputForm[v[1]], Head[v[1]], AtomQ[v[1]]}
evaluate to {v⎵1, Symbol, True}
. InputForm[Array[v,5]]
prints {v⎵1, v⎵2, v⎵3, v⎵4, v⎵5}
, and we can sometimes write v[1]
and sometimes v⎵1
.
Simply paste this function into your notebook and evaluate it for each indexed symbol. Each nonnegative integer subscript will evaluate the symbol's function exactly once. The first version evaluates Context[FUN]<>SymbolName[FUN] every time a new subscript is encountered.
defineIndexedVariable[FUN_Symbol] :=
FUN[ix_Integer /; ix ≥ 0] := With[{
v=Symbol[Context[FUN]<>SymbolName[FUN]<>"⎵"<>ToString[ix]]
},
Format[v] = Subscript[FUN,ix];
FUN[ix] = v
]
For one symbol, optimize it by hand and specify context explicitly everywhere:
FUN`FUN[ix_Integer /; ix ≥ 0] := With[{
v=Symbol["FUN`FUN⎵"<>ToString[ix]]
},
Format[v] = Subscript[FUN`FUN,ix];
FUN`FUN[ix] = v
]
Or get the same optimization with this version:
defineIndexedVariable[FUN_Symbol] := With[{
prefix = Context[FUN] <> SymbolName[FUN] <> "⎵"
},
FUN[ix_Integer /; ix >= 0] := With[{
v = Symbol[prefix <> ToString[ix]]
},
Format[v] = Subscript[FUN, ix];
FUN[ix] = v
]
]
The Context[FUN]
prefix ensures that all of the new symbols will be
in the same context as the function definition. The FUN[ix] =
memoizes the function so Symbol
is called only once for each distinct index, and the Format[v]
definition is made only once. The absence of a semicolon after the FUN[ix] = v
is absolutely essential.
After defineIndexedVariable[v]
, we get (OutputForm
on a text terminal)
v
v[1] 1
Head[v[1]] Symbol
AtomQ[v[1]] True
Dt[v[x], x] v'[x]
Dt[v[y], x] Dt[y, x] v'[y]
Dt[v , x]
Dt[v[1], x] 1
Dt[v1, x] Dt[v1, x]
D[v[1], x] 0
Information["v"]
:
Global`v
v[1] = v⎵1
v[ix$_Integer/;ix$>=0]:=With[{v$=Symbol["Global`v⎵"<>ToString[ix$]]},Format[v$]=Subscript[v,ix$];v[ix$]=v$]
Using the standard front end, ??v does not showv⎵1
. But InputForm[Array[x,5]]
prints {v⎵1, v⎵2, v⎵3, v⎵4, v⎵5}
Code that printed the above tables:
Function[x,{Table[" ",{Length[x]}],HoldForm/@Unevaluated[x],x}, HoldAll][{v[1],InputForm[v[1]],Head[v[1]],AtomQ[v[1]],Dt[v[x],x],Dt[v[y],x],Dt[v[1],x],Dt[v1,x],D[v[1],x]}]//Transpose//TableForm//Print
Indexed
? $\endgroup$Indexed[x, 3] = 4
gives Set::write: Tag Indexed in Indexed[x,3] is Protected. >> How do you propose to use it as indexed variables? $\endgroup$We have learned that we should not use Subscript for indexing variables
... You shouldn't have any problem, provided you don't mix subscripted $x_2$ and non-subscripted $x$ at the same time. $\endgroup$