Passing a matrix as a function argument



I am trying to do the following:

q = Table[i + j, {i, 1, 15}, {j, 1, 10}];
normalize[mat_] := (temp = Transpose[mat[[2 ;;, 5 ;;]]];
  temp1 = Transpose[N[Map[Normalize[#] &, temp]]];
  mat[[2 ;;, 5 ;;]] = temp1; Return[mat])

I get the following error:

in the part assignment is not a symbol. >>

Can you please help me in finding out what is wrong? I am new to Mathematica.


Posted 2012-08-03T22:20:22.050

Reputation: 803



To complement the other answer presented, I would like to suggest that it is often cleaner not to carry around additional symbols such as temp and temp1 in your code.

If we want to modify a copy of the matrix we still need a "proxy" symbol which I will create with Module. (This is safer than Block as the latter will replace any symbols seen in the course of evaluation, even ones that are in the array; for example if x were in the array and I used Block it would conflict.) You also do not need explicit Return except in special circumstances.

normalize[mat_] :=
 Module[{x = mat},
   x[[2 ;;, 5 ;;]] = 
     N @ Map[Normalize, x[[2 ;;, 5 ;;]]\[Transpose]]\[Transpose];

Or, to modify the array in-place no proxy is needed, but HoldFirst is:

SetAttributes[normalizeInPlace, HoldFirst]

normalizeInPlace[mat_] :=
   mat[[2 ;;, 5 ;;]] = 
     N @ Map[Normalize, mat[[2 ;;, 5 ;;]]\[Transpose]]\[Transpose];


Posted 2012-08-03T22:20:22.050

Reputation: 259 163

which is like faster then to use? is first one make copy of matrix which is bad for big matrix, so what to do now, use the holdfirst thing and pass by reference like in c, so no copy is made. copying large matrix is bad for memory. what to do? – Robert H – 2012-08-05T09:49:00.200

@Robert I think you answer your own question, or am I mistaken? If it is practical to modify in-place I surely would, but if you end up needing a copy of the original anyway that's something to consider. Typically you will find that in-place modifications using Part are faster, especially when the percent of the array that is modified is small. (In this case it is fairly large, but if you were only modifying one row or column in a large array the difference would be clear.) – Mr.Wizard – 2012-08-05T17:14:12.193



You can use the HoldAll attribute. Suppose I want a function that takes some list or matrix as input and sets its 4th element to 42. This can be done like so:

SetAttributes[f, HoldAll]
f[m_] := (m[[4]]= 42; m)


t = RandomInteger[{0, 10}, {5, 2}]

{{6, 2}, {7, 4}, {0, 4}, {10, 6}, {8, 7}}
{{6, 2}, {7, 4}, {0, 4}, 42, {8, 7}}

In your case, it would be

ClearAll[normalize, q, q1];
q = Table[i + j, {i, 1, 15}, {j, 1, 10}];
SetAttributes[normalize, HoldAll];
normalize[mat_] := (temp = Transpose[mat[[2 ;;, 5 ;;]]];
  temp1 = Transpose[N[Map[Normalize[#] &, temp]]];
  mat[[2 ;;, 5 ;;]] = temp1; Return[mat])
q1 = normalize[q];


The HoldAll attribute tells the evaluator not to evaluate the argument of your function before trying to do operations on it. Otherwise, look at what happens (using Trace which shows what is being evaluated):

ClearAll[f, g];
SetAttributes[f, HoldAll]
f[m_] := (m[[4]] = 42; m)

g[m_] := (m[[4]] = 42; m)

t = RandomInteger[{0, 10}, {5}]
f[t] // Trace

{7, 6, 3, 7, 6}


while without HoldAll,

g[t] // Trace

issues an error and dumps some stuff on the screen, most relevant of which (and immediately before the error) is this:

{7, 6, 3, 42, 6}[[4]] = 42

which is what causes the error. In the previous case, at this point there was a t[[4]]=42 which is fine.

You can think of this as passing by reference, versus passing by value if the HoldAll attribute is not set (although this is not entirely accurate).


Note that in this approach, you are manipulating the t that is in the global context. If you are writing more complicated code, you probably want to do what JM described.


Posted 2012-08-03T22:20:22.050

Reputation: 19 146


You need another temporary variable to be able to do what you want:

normalize[mat_] := Block[{matTemp = mat, temp, temp1},
  temp = Transpose[matTemp[[2 ;;, 5 ;;]]]; 
  temp1 = Transpose[N[Map[Normalize, temp]]];
  matTemp[[2 ;;, 5 ;;]] = temp1;

Note that in the line mat[[2 ;;, 5 ;;]] = temp1 of the original code, the mat is replaced by the matrix you have given as argument, and since you can't assign to a matrix of a numbers, you get that error you saw.

J. M.'s ennui

Posted 2012-08-03T22:20:22.050

Reputation: 115 520

Thanks! But can you explain this in terms of pointers? I was thinking, the function gets the pointer as reference and would modify the variable and return the pointer. Obviously, that is not happening. Can you please tell me what is happening? – preeti – 2012-08-04T03:03:16.900

There aren't any pointers here; this isn't C. To repeat: when you execute normalize[], all instances of the pattern mat_ are replaced by whatever argument you gave to normalize[]. Obviously, if the matrix of numbers that replaces mat appears to the left of Set[] (=), there will be an error, since you can't assign to a matrix of constants. – J. M.'s ennui – 2012-08-04T03:06:20.243