Yet another "simple" headscratcher

Josh English Joshua.R.English at gmail.com
Fri May 30 23:38:02 EDT 2014


I am trying to whip up a quick matrix class that can handle multiplication.

Should be no problem, except when it fails.

--- Begin
#!/usr/bin/env python
# _*_ coding: utf-8

from operator import mul

class Matrix(object):
    """Matrix([data])
    Data should be a list of equal sized lists.
    Defaults to a 2d identity matrix
    """
    def __init__(self, data=None):
        if data is None:
            data = [[1,0], [0,1]]

        self.data = []
        if isinstance(data, (list, tuple)):
            ncols = len(data[0])
            for row in data:
                if len(row) != ncols:
                    raise ValueError("Rows are unequal lengths")
                self.data.append(row)
        self.size = (len(self.data), len(self.data[0]))

    def get_row(self, idx):
        if (0 <= idx < self.size[0]):
            return self.data[idx]
        else:
            raise ValueError("Bad row")

    def get_col(self, idx):
        if (0 <= idx < self.size[1]):
            return list(d[idx] for d in self.data)
        else:
            raise ValueError("Bad column index")

    def __mul__(self, other):
        if not isinstance(other, (Matrix,int, float)):
            raise ValueError("Cannot multiply by given value")
        if isinstance(other, (int, float)):
            res = []
            for row in self.data:
                res.append([d*other for d in row])
            return Matrix(res)
        # left with a matrix
        res = zero_matrix(self.size[0], other.size[1])
        for i in range(res.size[0]):
            for j in range(res.size[1]):
                print i, j, self.get_row(i), other.get_col(j),
                temp = map(mul, self.get_row(i), other.get_col(j))

                print temp,
                t = sum(temp)
                print t
                res.data[i][j] = t
                print res.data
        return res

    def as_string(self):
        # return a list of lines that look pretty
        stringed =[]
        for row in self.data:
            stringed.append(map(str, row))
        widths = []
        for col in range(self.size[1]):
            column = [s[col] for s in stringed]
            widths.append(max(map(len, column)))
        item_format = "{:>%s}"
        format_items = [item_format % w for w in widths]
        format_string = "  ".join(format_items)

        formatted = [format_string.format(*s) for s in stringed]
        return formatted

def zero_matrix(rows, cols):
    row = [0] * cols
    data = []
    for r in range(rows):
        data.append(row)

    return Matrix(data)

M = Matrix(([1, 0], [0, -1]))

N = M*4


print '\n'.join(M.as_string())
print '-'
print '\n'.join(N.as_string())


print '-'
S = N * M
print '\n'.join(S.as_string())
--- END

For some reason, my output from this is:

1   0
0  -1
-
4   0
0  -4
-
0 0 [4, 0] [1, 0] [4, 0] 4
[[4, 0], [4, 0]]
0 1 [4, 0] [0, -1] [0, 0] 0
[[4, 0], [4, 0]]
1 0 [0, -4] [1, 0] [0, 0] 0
[[0, 0], [0, 0]]
1 1 [0, -4] [0, -1] [0, 4] 4
[[0, 4], [0, 4]]
0  4
0  4
>>>

The print lines prove to me that the logic is working, but for some reason, assigning the sum to a particular item in a particular row is assigning the same row values to every row.

This should be one of those really simple Python things, but for the life of me I don't see it.

The first [[4, 0], [4, 0]] is clearly wrong. In each step, this algorithm is repeating the row.

Any ideas as to why this is happening?

Python 2.7.5, Windows 7, so nothing exotic.

Josh



More information about the Python-list mailing list