I'm trying to implement matrix class for simple operations with plain python (no numpy and etc.).
Here is part of it:
class Matrix(list):
def __getitem__(self, item):
try:
return list.__getitem__(self, item)
except TypeError:
rows, cols = item
return [row[cols] for row in self[rows]]
It allows to do things like this:
m = Matrix([[i+j for j in [0,1,2,3]] for i in [0,4,8,12]])
print(m[0:2, 0:2])
will print: [[0, 1], [4, 5]]
I also want to be able to add/multiply all submatrix elements by given value, like:
m[0:2, 0:2] += 1
print(m[0:2, 0:2])
should print: [[1, 2], [5, 6]]
It's not clear which magic methods should I implement to make it work?
First, inheriting from list is a bad move here. A matrix doesn't support the kinds of operations a list does; for example, you can't append to or extend a matrix, and item assignment is completely different. Your matrix should contain a list, not be a list.
As for what magic methods you need, m[0:2, 0:2] += 1 roughly translates to the following:
temp = m.__getitem__((slice(0, 2), slice(0, 2)))
temp = operator.iadd(temp, 1)
m.__setitem__((slice(0, 2), slice(0, 2)), temp)
where operator.iadd tries temp.__iadd__, temp.__add__, and (1).__radd__ to perform the addition.
You need to implement __getitem__ and __setitem__ to retrieve the submatrix and assign the new submatrix. Additionally, __getitem__ will need to return a matrix, rather than a list.
You should probably implement both __add__ and __iadd__; while __add__ alone would be sufficient for this case, __iadd__ will be necessary for operations like m += 1 to work in-place instead of replacing m with a new matrix object.
NO. __iadd__ will do the trick for you if the magic was:
m += 2
But the magic is executed over m[0:2, 0:2]. You need to ensure that when slicing your matrix you get a different object, and not a list of lists, since list of lists do not support __iadd__.
Related
I want to make a function in python which receives as arguments a matrix, a coordinate for the line and another coordinate for the column. For example: A matrix m=[[1,2,3], [4,5,6]] and the function will receive the arguments (m,0,0)
It should return 1 (Which is the number located in position 0,0 in the matrix).
Think of it as a list of lists rather than a "matrix", and the logic becomes more obvious. Matrix m has two elements: m[0] = [1, 2, 3] and m[1] = [4, 5, 6]. So accessing a single value from within those lists requires another index. For example, m[0][1] = 2.
def matrix(m, a, b):
return m[a][b] # element b from list a in list m
If you really want to use a matrix, consider numpy.
I am trying to use itertools.product to manage the bookkeeping of some nested for loops, where the number of nested loops is not known in advance. Below is a specific example where I have chosen two nested for loops; the choice of two is only for clarity, what I need is a solution that works for an arbitrary number of loops.
This question provides an extension/generalization of the question appearing here:
Efficient algorithm for evaluating a 1-d array of functions on a same-length 1d numpy array
Now I am extending the above technique using an itertools trick I learned here:
Iterating over an unknown number of nested loops in python
Preamble:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [idx1, idx2]
func_table = []
for items in product(*joint):
f = trivial_functional(*items)
func_table.append(f)
At the end of the above itertools loop, I have a 12-element, 1-d array of functions, func_table, each element having been built from the trivial_functional.
Question:
Suppose I am given a pair of integers, (i_1, i_2), where these integers are to be interpreted as the indices of idx1 and idx2, respectively. How can I use itertools.product to determine the correct corresponding element of the func_table array?
I know how to hack the answer by writing my own function that mimics the itertools.product bookkeeping, but surely there is a built-in feature of itertools.product that is intended for exactly this purpose?
I don't know of a way of calculating the flat index other than doing it yourself. Fortunately this isn't that difficult:
def product_flat_index(factors, indices):
if len(factors) == 1: return indices[0]
else: return indices[0] * len(factors[0]) + product_flat_index(factors[1:], indices[1:])
>> product_flat_index(joint, (2, 1))
9
An alternative approach is to store the results in a nested array in the first place, making translation unnecessary, though this is more complex:
from functools import reduce
from operator import getitem, setitem, itemgetter
def get_items(container, indices):
return reduce(getitem, indices, container)
def set_items(container, indices, value):
c = reduce(getitem, indices[:-1], container)
setitem(c, indices[-1], value)
def initialize_table(lengths):
if len(lengths) == 1: return [0] * lengths[0]
subtable = initialize_table(lengths[1:])
return [subtable[:] for _ in range(lengths[0])]
func_table = initialize_table(list(map(len, joint)))
for items in product(*map(enumerate, joint)):
f = trivial_functional(*map(itemgetter(1), items))
set_items(func_table, list(map(itemgetter(0), items)), f)
>>> get_items(func_table, (2, 1)) # same as func_table[2][1]
<function>
So numerous answers were quite useful, thanks to everyone for the solutions.
It turns out that if I recast the problem slightly with Numpy, I can accomplish the same bookkeeping, and solve the problem I was trying to solve with vastly improved speed relative to pure python solutions. The trick is just to use Numpy's reshape method together with the normal multi-dimensional array indexing syntax.
Here's how this works. We just convert func_table into a Numpy array, and reshape it:
func_table = np.array(func_table)
component_dimensions = [len(idx1), len(idx2)]
func_table = np.array(func_table).reshape(component_dimensions)
Now func_table can be used to return the correct function not just for a single 2d point, but for a full array of 2d points:
dim1_pts = [3,1,2,1,3,3,1,3,0]
dim2_pts = [0,1,2,1,2,0,1,2,1]
func_array = func_table[dim1_pts, dim2_pts]
As usual, Numpy to the rescue!
This is a little messy, but here you go:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [enumerate(idx1), enumerate(idx2)]
func_map = {}
for indexes, items in map(lambda x: zip(*x), product(*joint)):
f = trivial_functional(*items)
func_map[indexes] = f
print(func_map[(2, 0)](5)) # 40 = (3+5)*5
I'd suggest using enumerate() in the right place:
from itertools import product
def trivial_functional(i, j): return lambda x : (i+j)*x
idx1 = [1, 2, 3, 4]
idx2 = [5, 6, 7]
joint = [idx1, idx2]
func_table = []
for items in product(*joint):
f = trivial_functional(*items)
func_table.append(f)
From what I understood from your comments and your code, func_table is simply indexed by the occurence of a certain input in the sequence. You can access it back again using:
for index, items in enumerate(product(*joint)):
# because of the append(), index is now the
# position of the function created from the
# respective tuple in join()
func_table[index](some_value)
The sort() and reverse() methods modify the list in place for economy of space when sorting or reversing a large list. To remind you that they operate by side effect, they don’t return the sorted or reversed list.
The above text can be found at http://docs.python.org/2/library/stdtypes.html#mutable-sequence-types
What does "modify the list in place for economy of space" mean?
Example:
x = ["happy", "sad"]
y = x.reverse()
would return None to y. So then why does,
x.reverse()
Successfully reverse x?
What does "modify the list in place for economy of space" mean?
What this means is that it does not create a copy of the list.
why does, x.reverse() Successfully reverse x?
I don't understand this question. It does this because that's what it's designed to do (reverse x and return None).
Note that sort() and reverse() have counterparts that don't modify the original and return a copy. These functions are called sorted() and reversed():
In [7]: x = [1, 2, 3]
In [8]: y = list(reversed(x))
In [9]: x
Out[9]: [1, 2, 3]
In [10]: y
Out[10]: [3, 2, 1]
list.reverse reverses the list in-place and returns None, it's designed to do so, similar to append, remove, extend, insert, etc.
In [771]: x = ["happy", "sad"]
In [772]: x.reverse()
In [773]: x
Out[773]: ['sad', 'happy']
In almost any programming language there are two kinds of callable definitions: functions and procedures.
Functions are methods or subroutines that do some processing and return a value. For instance, a function to sum two integers a and b will return the result of the sum a + b.
In the other hand, procedures are pretty much the same (even in the syntax in most languages) with the slight difference that don't return a value, and of course they are used by their side effects, meaning that they change the state of something or just process some data and save it or just print it out to a file.
So in this case, reverse would act as a procedure, which changes the state of the list being reversed (by reversing it), and here is how this can be done without extra space:
def reverse(l):
for i in range(len(l) / 2):
l[i], l[-i-1] = l[-i-1], l[i]
Notice that a new list is never created, instead, what the code does is to interchange the elements of the list l in place by swapping the first and the last, the second and the penultimate and so on until the element in the half of the list.
Hope this helps you understand ;)
I know that there are certain "special" methods of various objects that represent operations that would normally be performed with operators (i.e. int.__add__ for +, object.__eq__ for ==, etc.), and that one of them is list.__setitem, which can assign a value to a list element. However, I need a function that can assign a list into a slice of another list.
Basically, I'm looking for the expression equivalent of some_list[2:4] = [2, 3].
The line
some_list[2:4] = [2, 3]
will also call list.__setitem__(). Instead of an index, it will pass a slice object though. The line is equivalent to
some_list.__setitem__(slice(2, 4), [2, 3])
It depends on the version of Python. For 3.2, __setitem__ does the job:
Note Slicing is done exclusively with the following three methods. A call like
a[1:2] = b
is translated to
a[slice(1, 2, None)] = b
and so forth. Missing slice items are always filled in with None.
I know you can create easily nested lists in python like this:
[[1,2],[3,4]]
But how to create a 3x3x3 matrix of zeroes?
[[[0] * 3 for i in range(0, 3)] for j in range (0,3)]
or
[[[0]*3]*3]*3
Doesn't seem right. There is no way to create it just passing a list of dimensions to a method? Ex:
CreateArray([3,3,3])
In case a matrix is actually what you are looking for, consider the numpy package.
http://docs.scipy.org/doc/numpy/reference/generated/numpy.zeros.html#numpy.zeros
This will give you a 3x3x3 array of zeros:
numpy.zeros((3,3,3))
You also benefit from the convenience features of a module built for scientific computing.
List comprehensions are just syntactic sugar for adding expressiveness to list initialization; in your case, I would not use them at all, and go for a simple nested loop.
On a completely different level: do you think the n-dimensional array of NumPy could be a better approach?
Although you can use lists to implement multi-dimensional matrices, I think they are not the best tool for that goal.
NumPy addresses this problem
Link
>>> a = array( [2,3,4] )
>>> a
array([2, 3, 4])
>>> type(a)
<type 'numpy.ndarray'>
But if you want to use the Python native lists as a matrix the following helper methods can become handy:
import copy
def Create(dimensions, item):
for dimension in dimensions:
item = map(copy.copy, [item] * dimension)
return item
def Get(matrix, position):
for index in position:
matrix = matrix[index]
return matrix
def Set(matrix, position, value):
for index in position[:-1]:
matrix = matrix[index]
matrix[position[-1]] = value
Or use the nest function defined here, combined with repeat(0) from the itertools module:
nest(itertools.repeat(0),[3,3,3])
Just nest the multiplication syntax:
[[[0] * 3] * 3] * 3
It's therefore simple to express this operation using folds
def zeros(dimensions):
return reduce(lambda x, d: [x] * d, [0] + dimensions)
Or if you want to avoid reference replication, so altering one item won't affect any other you should instead use copies:
import copy
def zeros(dimensions):
item = 0
for dimension in dimensions:
item = map(copy.copy, [item] * dimension)
return item