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?

  • $\begingroup$ Try with myF[kmax_] := ... . $\endgroup$ – b.gates.you.know.what Dec 4 '12 at 14:51
  • $\begingroup$ Also myF[kmax_Integer] := ... will give you some defence against real values creeping into your function. $\endgroup$ – image_doctor Dec 4 '12 at 15:01
  • 1
    $\begingroup$ 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. $\endgroup$ – 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]].


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.

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

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.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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