I see two ways to do the kind of thing desired. You could make the parameter an argument to every function, or have the parameter be a global symbol and not an argument to any function.
Parameters as arguments
Put an argument in each function representing the parameter:
z[1, t_] := {1, 1};
B[t_] := {{t, 1}, {-1, t}};
z[n_Integer, t_] /; n > 0 := B[t].z[n - 1, t];
{z[2, t], z[2, s], z[2, 100]}
(* {{1 + t, -1 + t}, {1 + s, -1 + s}, {101, 99}} *)
Parameters as global variables
Make sure t
is undefined when z
and B
are defined. (I clear any definitions of z
and B
as well.)
Clear[t];
Clear[B, z]; (* clear previous definitions *)
z[1] = {1, 1};
B = {{t, 1}, {-1, t}};
z[n_Integer] /; n > 0 := B.z[n - 1];
{z[2], z[2] /. t -> s, z[2] /. t -> 100}
(* {{1 + t, -1 + t}, {1 + s, -1 + s}, {101, 99}} *)
Memoizing
You can often improve performance of recursively defined function if you use a technique called "memoization." An good discussion can be found What does the construct f[x_] := f[x] = ... mean?, cited in a comment by @whuber. The Mathematica documentation has a good introductory tutorial, "Functions That Remember Values They Have Found", too.
For example, in the example using t
as a global variable, the definition of z
would be
z[n_Integer] /; n > 0 := z[n] = B.z[n - 1]
See the links for further discussion.
Discussion
Each approach can do what you want, and each is probably used often. The biggest consideration is that if the parameter t
is a global variable, then generally you want to avoid it being set (no t = 3
for example). It might cause unexpected behavior. Thus I have a slight preference for using the argument approach
Why _Integer.../; n > 0
instead of _
?
If the definition of z
begins z[n_, t_] :=...
, then for an undefined symbol n
, z[n, t]
matches the definition and is expanded. This leads to z[n-1,t]
, then z[n-2,t]
etc. Since z[1,t]
is never reached, the recursion goes until the limit is hit. The n_Integer
restricts the definition to matching only when n
is an integer. The Condition
/; n > 0
further restricts the definition to positive integers. This guarantees that recursive definition will be applied only to positive n
.
What went wrong in the original definitions?
What is wrong with the first line has to do with how it matches the third line. The recursive definition of z
has two arguments and so it will never lead to this pattern:
z[1] := {1, 1}
In the second, t
is a global symbol. If it has a value, it will be substituted whenever B
is evaluated, because B
is defined using SetDelayed
.
B := {{t, 1}, {-1, t}}
Another difficulty arises in the different way z
and B
are defined.
z[n_, t_] := B.z[n - 1, t]
The t
in the definition of z
is not a variable per se, just the name of the second argument. Technically, it is the Pattern
Blank[]
that matches whatever is passed as the second argument. It has nothing to do with the global t
in B
. For instance, z[2, s]
will expand to
{{t, 1}, {-1, t}}.z[1, s]
where s
would be whatever was passed to z
and does not have to be the same as t
. (Of course, the recursion will go on until $RecursionLimit
is hit, because of the mismatch with the first definition.)
:=
by set=
in the first two lines. (2) When you run this, look at the error messages. Think about how MMA is going to tell when to stop the recursion. (Hint:z[1]
is not the same asz[1,t]
.) BTW, you might be interested inMatrixExp
. $\endgroup$ – whuber Mar 16 '13 at 3:22z[1, t_] := {1, 1}
. Incidentally, you would appreciate the information you get in a search for memoizing. See mathematica.stackexchange.com/questions/2639/… for instance. Your code is still a little whacky, becauseB
implicitly has the literal symbolt
within it. It will work with the change I suggested, but if you supply anything other thant
for the second argument ofz
, be prepared for surprises. $\endgroup$ – whuber Mar 16 '13 at 3:51