Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #72325 > unrolled thread

Yet another "simple" headscratcher

Started byJosh English <Joshua.R.English@gmail.com>
First post2014-05-30 20:38 -0700
Last post2014-05-30 23:46 -0700
Articles 5 — 4 participants

Back to article view | Back to comp.lang.python


Contents

  Yet another "simple" headscratcher Josh English <Joshua.R.English@gmail.com> - 2014-05-30 20:38 -0700
    Re: Yet another "simple" headscratcher Josh English <Joshua.R.English@gmail.com> - 2014-05-30 20:55 -0700
    Re: Yet another "simple" headscratcher Gary Herron <gary.herron@islandtraining.com> - 2014-05-30 20:57 -0700
    Re: Yet another "simple" headscratcher Ian Kelly <ian.g.kelly@gmail.com> - 2014-05-30 21:54 -0600
      Re: Yet another "simple" headscratcher wxjmfauth@gmail.com - 2014-05-30 23:46 -0700

#72325 — Yet another "simple" headscratcher

FromJosh English <Joshua.R.English@gmail.com>
Date2014-05-30 20:38 -0700
SubjectYet another "simple" headscratcher
Message-ID<a7dbde77-6bec-4b04-a940-5e8beb926232@googlegroups.com>
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

[toc] | [next] | [standalone]


#72326

FromJosh English <Joshua.R.English@gmail.com>
Date2014-05-30 20:55 -0700
Message-ID<4bf8faee-f4ee-46d6-99f8-ad43a5a59cab@googlegroups.com>
In reply to#72325
Mea culpa, gang.

I found it.

It had absolutely nothing to do with the multiplication.

It was in zero_matrix.

I feel like a fool.

Josh

[toc] | [prev] | [next] | [standalone]


#72327

FromGary Herron <gary.herron@islandtraining.com>
Date2014-05-30 20:57 -0700
Message-ID<mailman.10503.1401508915.18130.python-list@python.org>
In reply to#72325
On 05/30/2014 08:38 PM, Josh English wrote:
> ...
>
> def zero_matrix(rows, cols):
>      row = [0] * cols
>      data = []
>      for r in range(rows):
>          data.append(row)
>
>      return Matrix(data)

There is a simple and common newbie mistake here.    It looks like you 
are appending several copies of a zero row to data, but in fact you are 
appending multiple references to a single row.  (The hint is that you 
only created *one* row.)

Put the
    row = [0] * cols
inside the loop so each append is using its own row rather than one 
shared row being used multiple times.


Here's a small example that demonstrates problem:

 >>> row = [0,0,0,0]
 >>> data = []
 >>> data.append(row)
 >>> data.append(row)
 >>> data[0][0] = 99
 >>> data
[[99, 0, 0, 0], [99, 0, 0, 0]]


Gary Herron


[toc] | [prev] | [next] | [standalone]


#72328

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-05-30 21:54 -0600
Message-ID<mailman.10504.1401508949.18130.python-list@python.org>
In reply to#72325
On Fri, May 30, 2014 at 9:38 PM, Josh English
<Joshua.R.English@gmail.com> wrote:
> I am trying to whip up a quick matrix class that can handle multiplication.
>
> Should be no problem, except when it fails.
>
> [SNIP]
>
> def zero_matrix(rows, cols):
>     row = [0] * cols
>     data = []
>     for r in range(rows):
>         data.append(row)

Each row of the matrix that you create here is the *same* list, not
different lists that happen to be equal.  So when you mutate one row,
you mutate all of them.  See:
https://docs.python.org/3/faq/programming.html#how-do-i-create-a-multidimensional-list

[toc] | [prev] | [next] | [standalone]


#72329

Fromwxjmfauth@gmail.com
Date2014-05-30 23:46 -0700
Message-ID<9660e790-4734-4f41-a0bf-840b207c5a15@googlegroups.com>
In reply to#72328
>>> # from my lib
>>> def NewMat(nr, nc, val=0.0):
...     val = float(val)
...     return [[val] * nc for i in range(nr)]
...     
>>> import vmio6
>>> aa = NewMat(2, 3)
>>> vmio6.pr(aa)
(   0.00000e+000  0.00000e+000  0.00000e+000 )
(   0.00000e+000  0.00000e+000  0.00000e+000 )
>>> aa[0][0] = 3.1416
>>> vmio6.pr(aa)
(   3.14160e+000  0.00000e+000  0.00000e+000 )
(   0.00000e+000  0.00000e+000  0.00000e+000 )
>>> aa[1][1] = 1.2345
>>> vmio6.pr(aa)
(   3.14160e+000  0.00000e+000  0.00000e+000 )
(   0.00000e+000  1.23450e+000  0.00000e+000 )
>>>

jmf

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web