# Python bug in my matrix class

• (3 Pages)
• 1
• 2
• 3

## 32 Replies - 11778 Views - Last Post: 26 July 2012 - 04:05 PMRate Topic: //<![CDATA[ rating = new ipb.rating( 'topic_rate_', { url: 'http://www.dreamincode.net/forums/index.php?app=forums&module=ajax&section=topics&do=rateTopic&t=286624&amp;s=be6c39c84e57c5c6e065cb89d01a413f&md5check=' + ipb.vars['secure_hash'], cur_rating: 0, rated: 0, allow_rate: 0, multi_rate: 1, show_rate_text: true } ); //]]>

### #1 carnivroar

• D.I.C Regular

Reputation: 29
• Posts: 387
• Joined: 18-September 11

# Python bug in my matrix class

Posted 22 July 2012 - 05:38 PM

```class Matrix:
M = None
N = None
matrix = None

def __init__(self, N, M):
self.N = N
self.M = M
self.matrix = [[0]*M]*N

def setMatrix(self, matrix):
if (self.badMatrix(matrix)):
raise Exception("Error: unmatching dimensions.")
self.matrix = matrix

def toString(self):
for i in range(self.N):
for j in range(self.M):
print(self.matrix[i][j], end=" ")
print()

def plus(self, other):
if (other.N != self.N | other.M != self.M):
raise Exception("Error: cannot add matrices of different dimensions.")
result = Matrix(self.N, self.M)
for i in range(self.N):
for j in range(self.M):
result.matrix[i][j] = self.matrix[i][j] + other.matrix[i][j]
return result

def minus(self, other):
if (other.N != self.N | other.M != self.M):
raise Exception("Error: cannot subtract matrices of different dimensions.")
result = Matrix(self.N, self.M)
for i in range(self.N):
for j in range(self.M):
result.matrix[i][j] = self.matrix[i][j] - other.matrix[i][j]
print(result.matrix[i][j]) #<-- but this gives me correct result... huh?
return result

def badMatrix(self, matrix):
if (len(matrix) != self.N):
return True
for i in range(self.N):
if (len(matrix[i]) != self.M):
return True
return False

```

```from Matrix import *

A = Matrix(3, 3)
A.setMatrix([[1,2,3],
[4,5,6],
[7,8,9]])

B = Matrix(3, 3)
B.setMatrix([[9,8,7],
[6,5,4],
[3,2,1]])

C = A.plus(B)/>
C.toString()

D = A.minus(B)/>
D.toString()

```

C gives met he correct value, but D doesn't. The plus and minus functions are practically identical... any idea what's wrong?

This post has been edited by carnivroar: 22 July 2012 - 05:40 PM

Is This A Good Question/Topic? 0

## Replies To: Python bug in my matrix class

### #2 carnivroar

• D.I.C Regular

Reputation: 29
• Posts: 387
• Joined: 18-September 11

## Re: Python bug in my matrix class

Posted 22 July 2012 - 07:07 PM

Actually neither of them (plus or minus) are working. I seriously can't figure out what is wrong.
Was This Post Helpful? 0

### #3 Simown

• Blue Sprat

Reputation: 321
• Posts: 650
• Joined: 20-May 10

## Re: Python bug in my matrix class

Posted 22 July 2012 - 07:11 PM

You seem to be trying to use the pipe "|" as an "or"? I'm afraid it doesn't work like that in Python.

You want the word "or"!

condition1 or conditon2 or condition3

Which may be where your problem lies? Looking at it quickly, the plus and minus methods look fine.

Do you realise you are changing the value of "A" in the first assignment? The values in the matrix "A" are being reassigned in your functions; lists are mutable.

Also, it's better to have a __str__ method rather than toString() i.e.:

```def __str__(self):
for i in range(self.N):
for j in range(self.M):
print(self.matrix[i][j], end=" ")
print()

```

Then if you say print(matrix), it will call the __str__ method for you, and will have the same result as calling toString() without explicitly naming the method.
Was This Post Helpful? 1

### #4 atraub

• Pythoneer

Reputation: 820
• Posts: 2,197
• Joined: 23-December 08

## Re: Python bug in my matrix class

Posted 22 July 2012 - 08:09 PM

Using list comprehensions and the join method, both of which you can read about on this thread, I wrote out a __str__ method in 1 line

```def __str__(self):
return '\n'.join([' '.join([str(value) for value in row]) for row in self.matrix])

```

Was This Post Helpful? 2

### #5 carnivroar

• D.I.C Regular

Reputation: 29
• Posts: 387
• Joined: 18-September 11

## Re: Python bug in my matrix class

Posted 22 July 2012 - 08:15 PM

The problem was with my __init__ function

This is what I have now

```
def __init__(self, N, M):
self.N = N
self.M = M
self.matrix = [[0 for col in range(M)] for row in range(N)]

```

Apparently what I did before was not a proper way to initialize a two-dimensional array.

And I wrote a __str__ function (just started reading about operator overloading in Python). Did _add__ and __sub__ as well.

```	def __str__(self):
return "".join(("\n".join(" ".join([str(self.matrix[j][i]) for i in range(self.M)]) for j in range(self.N))))

```

Thanks atraub for having written one, too. Good to compare it with what I came up with - yours was simpler.

This post has been edited by carnivroar: 22 July 2012 - 08:19 PM

Was This Post Helpful? 1

### #6 Simown

• Blue Sprat

Reputation: 321
• Posts: 650
• Joined: 20-May 10

## Re: Python bug in my matrix class

Posted 22 July 2012 - 08:24 PM

Your __init__ method was a valid way to create a 2d array before, but your new method works too.

I've got to go with atraub for the __str__ method, it's a lot clearer, in my opinion.
Was This Post Helpful? 0

### #7 atraub

• Pythoneer

Reputation: 820
• Posts: 2,197
• Joined: 23-December 08

## Re: Python bug in my matrix class

Posted 22 July 2012 - 08:30 PM

Hey, these improvements are great! I love your use of list comprehensions for the init.

This post has been edited by atraub: 22 July 2012 - 08:33 PM

Was This Post Helpful? 0

### #8 Simown

• Blue Sprat

Reputation: 321
• Posts: 650
• Joined: 20-May 10

## Re: Python bug in my matrix class

Posted 22 July 2012 - 08:43 PM

Oh no, I wasn't knocking it. It's great to see it evolve as more Python is learnt.

Maybe I'll seem brighter when I've had more sleep, it's nearly 5am here
Was This Post Helpful? 0

### #9 atraub

• Pythoneer

Reputation: 820
• Posts: 2,197
• Joined: 23-December 08

## Re: Python bug in my matrix class

Posted 22 July 2012 - 08:51 PM

Simown, on 22 July 2012 - 11:43 PM, said:

Oh no, I wasn't knocking it. It's great to see it evolve as more Python is learnt.

Maybe I'll seem brighter when I've had more sleep, it's nearly 5am here

Haha no worries, I wasn't implying anything like that. I just really like list comprehensions
Was This Post Helpful? 0

### #10 sepp2k

• D.I.C Lover

Reputation: 2251
• Posts: 3,445
• Joined: 21-June 11

## Re: Python bug in my matrix class

Posted 22 July 2012 - 10:54 PM

Simown, on 23 July 2012 - 04:11 AM, said:

You seem to be trying to use the pipe "|" as an "or"? I'm afraid it doesn't work like that in Python.

Actually it works perfectly fine. When used with booleans the only difference between | and or is that | does not short-circuit.

You can't use | with non-numeric operands though, but that's not a problem in this case.

That said, using or is certainly the better approach because it short-circuits and is easier to read.

Quote

Do you realise you are changing the value of "A" in the first assignment? The values in the matrix "A" are being reassigned in your functions; lists are mutable.

I don't see him changing the value of A anywhere except when he does A.setMatrix.

Quote

Your __init__ method was a valid way to create a 2d array before, but your new method works too.

No, his __init__ method was the reason his program didn't work. He's right about that.

The reason that the original __init__ method did not work is that [[0]*M]*N creates a list that contains N references to the same sublist. So changing one row, changes all the rows. Example:

```>>> res=[[0]*2]*2
>>> res[0][0]=42
>>> res
[[42, 0], [42, 0]]

```

Using list comprehensions the given expression will be evaluated each time, so you get N distinct sublists instead of the same sublist N times. So that's why it works fine with the new __init__.
Was This Post Helpful? 1

### #11 Simown

• Blue Sprat

Reputation: 321
• Posts: 650
• Joined: 20-May 10

## Re: Python bug in my matrix class

Posted 23 July 2012 - 02:30 AM

I stand corrected! That's what you get for posting so late.

With the "or", I meant to mention that, but as he seems to be just learning, I didn't want to overcomplicate it.

Yeah, the value of A doesn't change - I misread it.

Now I feel silly
Was This Post Helpful? 0

### #12 carnivroar

• D.I.C Regular

Reputation: 29
• Posts: 387
• Joined: 18-September 11

## Re: Python bug in my matrix class

Posted 23 July 2012 - 06:43 AM

I googled it but can't find an answer. Is there a function that overrides the = sign? I would like to use it instead of setMatrix().
Was This Post Helpful? 0

### #13 Simown

• Blue Sprat

Reputation: 321
• Posts: 650
• Joined: 20-May 10

## Re: Python bug in my matrix class

Posted 23 July 2012 - 06:47 AM

If I understand you correctly, you want underscore methods, like you overrided __str__.

Look at section 2.4 here: Python __Underscore__ Methods

Edit: Maybe that's not right, you want to override the assignment operator "="? Wouldn't that making assigning to other variables a little tricky?

Edit again, more thinking:

What if you assigned to the matrix in your __init__ method? i.e.:

```class Matrix:

def __init__(self, matrix):
self.N = len(matrix)
self.M = len(matrix[0]) # assuming they are all the same length, you should probably check
self.matrix = checkMatrix(matrix)

def checkMatrix(matrix):
# is it a valid matrix? Checks and validation

```

Then you can just make a new matrix:

```m = Matrix([[1,2,3], [4,5,6], [7,8,9]])
```

Is there a reason it is full of zeros to begin with?

This post has been edited by Simown: 23 July 2012 - 07:02 AM

Was This Post Helpful? 0

### #14 atraub

• Pythoneer

Reputation: 820
• Posts: 2,197
• Joined: 23-December 08

## Re: Python bug in my matrix class

Posted 23 July 2012 - 07:18 AM

Python has many magic methods, but overriding the assignment operator is no bueno. Why would you want to do that anyways?

EDIT:
Assignment is typically used on instantiation, but it is also used in things like swapping, or making multiple variables point to a single object... would you really want to adapt your code so that it doesn't mess people up for every circumstance they want to assign a matrix to a variable?

EDIT 2:
I get it! you don't want to completely override assignemnt, you want to override attribute assignment of the underlying matrix! You CAN do this with __setattr__(self, attr), but in that case, you'll need to use the dot notation to access the underlying matrix when you want to use that method.

ie:
```>>> x = Matrix()
>>> x.matrix = ([[1,2,3], [4,5,6], [7,8,9]])

```

EDIT 3:
But, there is a problem. __setattr__ is called anytime you want to set any attribute, and your matrix has 3. self.M, self.N, and self.matrix. I think you'll see that storing self.M and self.N is unnecessary as either value can be derived using len. However, if your user tried to do
```>>> x = Matrix()
>>> x.N = 4
```

then your program would likely break because I assume you'd throw the 4 through the badMatrix function. I'd get rid of those values and then you'll be all set for what you want to do!

This post has been edited by atraub: 23 July 2012 - 07:53 AM

Was This Post Helpful? 1

### #15 baavgai

• Dreaming Coder

Reputation: 6203
• Posts: 13,316
• Joined: 16-October 07

## Re: Python bug in my matrix class

Posted 23 July 2012 - 08:32 AM

Thought I'd play around with this. The idea of an initalizer with either data or dimension sounded like fun. I also though it would be nice to have a compare method and mash up the add and subtract.

Here's my playing:
```class Matrix:
# in case it hasn't been mentioned, don't do this
# you don't need it, you have self.
# M = None
# N = None
# matrix = None

def __init__(self, *rows):
if len(rows)==2 and isinstance(rows[0], int) and isinstance(rows[1], int):
m = rows[0]
n = rows[1]
self.matrix = [ [ 0 for j in range(n) ] for i in range(m) ]
else:
self._initData(rows)

def getM(self):
return len(self.matrix)

def getN(self):
return len(self.matrix[0])

def _initData(self, rows):
m = len(rows)
n = len(rows[0])
self.matrix = None
for i in range(1,n):
if len(rows[i])!=n:
raise Exception("Error: unmatching dimensions.")
self.matrix = [ [ rows[i][j] for j in range(n) ] for i in range(m) ]

def setMatrix(self, matrix):
self._initData(matrix)

def getValue(self, m, n):
return self.matrix[m][n]

def setValue(self, m, n, value):
self.matrix[m][n] = value

def __str__(self):
return '\n'.join([ ' '.join(str(self.getValue(m,n)) for n in range(self.getN())) for m in range(self.getM()) ])

def isSameSize(self, other):
return other.getN()==self.getN() and other.getM()==self.getM()

def _operProcess(self, matA, matB, oper):
matC = Matrix(matA.getM(), matA.getM())
for m in range(matC.getM()):
for n in range(matC.getN()):
matC.setValue(m, n, oper(matA.getValue(m,n),matB.getValue(m,n)))
return matC

def plus(self, other):
if not self.isSameSize(other):
raise Exception("Error: cannot add matrices of different dimensions.")
return self._operProcess(self, other, lambda x,y: x+y)

def minus(self, other):
if not self.isSameSize(other):
raise Exception("Error: cannot subtract matrices of different dimensions.")
return self._operProcess(self, other, lambda x,y: x-y)

def main():
A = Matrix(3, 3)
A.setMatrix([[1,2,3],
[4,5,6],
[7,8,9]])

B = Matrix([9,8,7],
[6,5,4],
[3,2,1])

print("A\n" + str(A))
print("B\n" + str(B)/>)
print("A.plus(B)/>\n" + str(A.plus(B)/>))
print("A.minus(B)/>\n" + str(A.minus(B)/>))

main()

```

Was This Post Helpful? 1

• (3 Pages)
• 1
• 2
• 3

 .related ul { list-style-type: circle; font-size: 12px; font-weight: bold; } .related li { margin-bottom: 5px; background-position: left 7px !important; margin-left: -35px; } .related h2 { font-size: 18px; font-weight: bold; } .related a { color: blue; }