# Use elements of Array inside function definition

I'm trying to define a function which modifies and sums over the elements of an array. Here is a very simplified version.

myF[kmax_] = Sum[v[[k]]/k, {k, 1, kmax}]


As you can see, each element between 1 and the function argument (kmax) is divided by its index and then summed with the others.

The problem is that mathematica isn't accepting that v[[k]] and complains that k isn't an integer.

Part::pspec: Part specification k is neither an integer nor a list of integers.


I tried replacing k with Round[k], but the problem remains. I even tried redefining the vector, where the elements are already divided by k, and then just summing over the first kmax elements:

myF[kmax_] = Total[Take[v, kmax]]


And I'm still getting error messages about the argument not being of the right type

Take::seqs: Sequence specification (+n, -n, {+n}, {-n}, {m, n}, or {m, n, s}) expected at position 2 in Take


So, am I doing something wrong? Is there any way to access array elements within a function definition?

-
Try with myF[kmax_] := ... . – b.gatessucks Dec 4 '12 at 14:51
Also myF[kmax_Integer] := ... will give you some defence against real values creeping into your function. – image_doctor Dec 4 '12 at 15:01
You should generaly avoid using Set (=) for function definitions, and you should avoid defining functions which depend on variables implicitly (like on your v here). For the latter, you can read some relevant discussion here. – Leonid Shifrin Dec 4 '12 at 15:17

The problem is that when Mathematica processes

myF[kmax_] = Sum[v[[k]]/k, {k, 1, kmax}]


it will immediately evaluate the right-hand side. And since it doesn't have a numeric value for kmax yet, it can't evaluate the Sum yet, which leads it to tell you that in v[[k]], k is not an integer, because it's still a symbol!

If you instead use a delayed set :=, the right-hand side will not be evaluated until the function is called where kmax has been given a value, so

 myF[kmax_] := Sum[v[[k]]/k, {k, 1, kmax}]


Then when you call myF[10] Mathematica evaluates Sum[v[[k]]/k, {k, 1, 10}], which means k gets an integer value before it evaluates v[[k]].

-

In addition to the distinction between = and := shown by jVincent, you can prevent Part from receiving a bad argument by introducing an auxiliary function with a restrictive pattern. This is most commonly done with the pattern _?NumericQ and you will see many examples if you search this site for NumericQ. Here I will use _Integer as that is more appropriate as an argument for Part.

v = {9, 7, 5, 3, 1};

part[x_, n_Integer] := x[[n]]

Sum[part[v, k]/k, {k, 1, kmax}]

Sum[part[{9, 7, 5, 3, 1}, k]/k, {k, 1, kmax}]


This expression is returned without errors.

-

While you said your example was a simplified version, if the full form is similar, I would consider using vector processing:

myF[kmax_] := Total[v[[;;kmax]]/Range[kmax]]


where v[[;;kmax]]/Range[kmax] is evaluated term wise, i.e. it gives $\frac{v_i}{i}$. There are a number of optimizations internally that make this faster than Sum.

Note, the use of SetDelayed (:=), like in jVincent's answer.

Edit: Additionally, I would consider using a Dot product instead:

myF[kmax_] := v[[;;kmax]].(1/Range[kmax])


which incorporates the vector processing from before, and improves readability.

-
Or he could define myF = v.(1/Range[Length[v]]) and call myF[[i]] instead of myF[i]. – Jens Dec 4 '12 at 17:59
@Jens, good point. I think programatically and conceptually that is superior. – rcollyer Dec 4 '12 at 21:01