I am currently writing a Linear Algebra module for Python 3.x wherein I deal with self-defined matrix objects.
Is there any way I can make the basic arithmetic operators like +, -, * adhere to my matrix objects? For example -
>>> A = matrix("1 2;3 4")
>>> B = matrix("1 0; 0 1")
>>> A + B
[2 2]
[3 5]
>>> A * A
[7 10]
[15 22]
Right now I have written separate functions for addition, multiplication, etc. but typing A.multiply(A) is much more cumbersome than simply A*A.
You are looking for special methods. Particularly at emulating numerical types section.
Also, as you're trying to implement matrices and matrices are containers, you may find useful to define custom container methods for your type.
UPDATE: Here is an example of custom objects using special methods to implement arithmetical operators:
class Value(object):
def __init__(self, x):
self.x = x
def __add__(self, other):
if not isinstance(other, Value):
raise TypeError
return Value(self.x + other.x)
def __mul__(self, other):
if not isinstance(other, Value):
raise TypeError
return Value(self.x * other.x)
assert (Value(2) + Value(3)).x == 5
assert (Value(2) * Value(3)).x == 6
Unless you're doing this specifically to learn or for practice you should look at numerical python, numpy, which is the de facto standard solution for basic linear algebra and matrices. It has a matrix class which does what you are looking for.
You can override the built in methods for numerical types.
class matrix:
def __init__(self, string_matrix):
self.matrix = string_matrix.split(";")
for i in range(len(self.matrix)):
self.matrix[i] = map(int, self.matrix[i].split())
def __add__(self, other):
return_matrix = [[i for i in row] for row in self.matrix]
for i in range(len(self.matrix)):
for j in range(len(self.matrix[i])):
return_matrix[i][j] = self.matrix[i][j] + other.matrix[i][j]
return list_to_matrix(return_matrix)
def __str__(self):
return repr(self.matrix)
def list_to_matrix(list_matrix):
string_form = ""
for row in list_matrix:
for item in row:
if (item != row[-1]): string_form += str(item) + " "
else: string_form += str(item)
if (row != list_matrix[-1]): string_form += ";"
return matrix(string_form)
You will probably want to include a couple of checks (such as adding matrices of different dimensions, or adding a matrix to something that is not a matrix, etc) but this works as a simple example. Also notice that I'm returning a matrix object using the list_to_matrix() function - if that isn't the desired functionality you can change it pretty readily. You would use a similar process for all other arithmetic functions you need to implement.
Output:
>>> a = matrix("3 4;1 4")
>>> b = matrix("2 3;0 0")
>>> print(a)
[[3, 4], [1, 4]]
>>> print(b)
[[2, 3], [0, 0]]
>>> print(a + b)
[[5, 7], [1, 4]]
As mentioned in one of the other answers, numpy might be a good resource to use for your matrix operations - a lot of this functionality is already built in.
>>> import numpy as np
>>> a = np.matrix("3 4;1 4")
>>> b = np.matrix("2 3;0 0")
>>> print(a)
[[3 4]
[1 4]]
>>> print(b)
[[2 3]
[0 0]]
>>> print(a + b)
[[5 7]
[1 4]]
If you define some special methods within the class, Python will call them for arithmetic operations. An example class that define addition, multiplication, division, and subtraction:
class motar:
def __add__(self, other): return "9999"
def __mul__(self, other): return "8888"
def __sub__(self, other): return "7777"
def __div__(self, other): return "6666"
m = [ motar() for x in range(2) ] # create two instances
# arithmetic operations on class instances will call
# ... the special methods defined above:
print m[0] + m[1]
print m[0] * m[1]
print m[0] - m[1]
print m[0] / m[1]
Gives:
9999
8888
7777
6666
Related
I'm trying to combine multiple numbers together in python 3.7 but I'm having no luck.
I want it to be like such:
1 + 4 + 5 = 145
I know this is simple but I'm getting nowhere!
You can use reduce to do this in a mathematical way
>>> l = [1, 4, 5]
>>>
>>> from functools import reduce
>>> reduce(lambda x,y: 10*x+y, l)
145
Alternatively, you can use string concat
>>> int(''.join(map(str, l)))
145
If you want to do this numerically, consider what base-10 numerals means:
145 = 1 * 10**2 + 4 * 10**1 + 5 * 10**0
So, you need to get N numbers that range from N-1 to 0, in lockstep with the digits. One way to do this is with enumerate plus a bit of extra arithmetic:
def add_digits(*digits):
total = 0
for i, digit in enumerate(digits):
total += digit * 10**(len(digits)-i-1)
return total
Now:
>>> add_digits(1, 4, 5)
145
Of course this only works with sequences of digits—where you know how many digits you have in advance. What if you wanted to work with any iterable of digits, even an iterator coming for a generator expression or something? Then you can rethink the problem:
1456 = ((1 * 10 + 4) * 10 + 5) * 10 + 6
So:
def add_digits(digits):
total = 0
for digit in digits:
total = total * 10 + digit
return total
>>> add_digits((1, 3, 5, 6))
1356
>>> add_digits(n for n in range(10) if n%2)
13579
Notice that you can easily extend either version to other bases:
def add_digits(*digits, base=10):
total = 0
for i, digit in enumerate(digits):
total += digit * base**(len(digits)-i-1)
return total
>>> hex(add_digits(1, 0xF, 2, 0xA, base=16))
'0x1f2a'
… which isn't quite as easy to do with the stringy version; you can't just do int(''.join(map(str, digits)), base), but instead need to replace that str with a function that converts to a string in a given base. Which there are plenty of solutions for, but no obvious and readable one-liner.
You should try casting the numbers as strings! When you do something like this
str(1)+str(4)+str(5)
You will get 145, but it will be a string. If you want it to be a number afterwards, then you can cast the whole thing as an integer.
int(str(1)+str(4)+str(5))
or just set the answer to a new variable and cast that as an integer.
You could just write a function that concatenates numbers or any other object/datatype as a string
concatenate = lambda *args : ''.join([str(arg) for arg in args])
a = 1
print(concatenate(4, 5, 6))
print(concatenate(a, MagicNumber(1), "3"))
But also in python you can make a class and write magic functions that control the way that objects of your class are added, subtracted etc. You could make a class to store a number and add it like you want to. You could save this code in a file and import it or paste it into your own script.
class MagicNumber():
value = 0
def __init__(self, value):
self.value = int(value)
def __str__(self):
return str(self.value)
def __int__(self):
return self.value
def __repr__(self):
return self.value
def __add__(self, b):
return MagicNumber(str(self)+str(b))
if __name__ == "__main__":
a = MagicNumber(4)
b = MagicNumber(5)
c = MagicNumber(6)
print(a+b+c)
#You could even do this but I strongly advise against it
print(a+5+6)
And heres a link to the documentation about these "magic methods"
https://docs.python.org/3/reference/datamodel.html
The easiest way to do this is to concat them as strings, and then parse it back into a number.
x = str(1) + str(4) + str(5)
print(int(x))
or
int(str(1) + str(4) + str(5))
I wanted to be able to divide entire lists by integers, floats, and other lists of equal length in Python, so I wrote the following little script.
class divlist(list):
def __init__(self, *args, **kwrgs):
super(divlist, self).__init__(*args, **kwrgs)
self.__cont_ = args[0]
self.__len_ = len(args[0])
def __floordiv__(self, other):
""" Adds the ability to floor divide list's indices """
if (isinstance(other, int) or isinstance(other, float)):
return [self.__cont_[i] // other \
for i in xrange(self.__len_)]
elif (isinstance(other, list)):
return [self.__cont_[i] // other[i] \
for i in xrange(self.__len_)]
else:
raise ValueError('Must divide by list, int or float')
My question: How can I write this in a simpler way? Do I really need the lines self.__cont_ and self.__len_? I was looking through the list's 'magic' methods and I couldn't find one that readily held this information.
An example of calling this simple class:
>>> X = divlist([1,2,3,4])
[1, 2, 3, 4]
>>> X // 2
[0, 1, 1, 2]
>>> X // [1,2,3,4]
[1, 1, 1, 1]
>>> X // X
[1, 1, 1, 1]
How can I write this in a simpler way?
By using self[i] instead of self.__cont_[i].
Do I really need the lines self.__cont_ and self.__len_?
No. Just use the regular methods of referring to a list, for example: [] and len().
As an aside, you might choose to have .__floordiv__() return a divlist instead of a list, so that you can continue to operate on the result.
class divlist(list):
def __floordiv__(self, other):
""" Adds the ability to floor divide list's indices """
if (isinstance(other, int) or isinstance(other, float)):
return [i // other for i in self]
elif (isinstance(other, list)):
# DANGER: data loss if len(other) != len(self) !!
return [i // j for i,j in zip(self, other)]
else:
raise ValueError('Must divide by list, int or float')
X = divlist([1,2,3,4])
assert X == [1, 2, 3, 4]
assert X // 2 == [0, 1, 1, 2]
assert X // [1,2,3,4] == [1, 1, 1, 1]
assert X // X == [1, 1, 1, 1]
Instead of examining the explicit types of each argument, assume that either the second argument is iterable, or it is a suitable value as the denominator for //.
def __floordiv__(self, other):
try:
pairs = zip(self, other)
except TypeError:
pairs = ((x, other) for x in self)
return [x // y for (x, y) in pairs]
You may want to check that self and other have the same length if the zip succeeds.
I have the following scipy.lti object that is basically an object representing a Laplace transform of an LTI system:
G_s = lti([1], [1, 2])
How to multiply such a transfer function with another one, such as i.e.:
H_s = lti([2], [1, 2])
#I_s = G_s * H_s <---- How to multiply this properly?
I guess I could do
I_s = lti(np.polymul([1], [2]), np.polymul([1, 2], [1, 2]))
But what if I want to do:
#I_s = H_s / (1 + H_s) <---- Does not work since H_s is an lti object
Is there an easy way to do this with scipy?
Interestingly, Scipy does not seem to supply that functionality. An alternative is converting the LTI system into a Sympy rational function. Sympy allows you to easily expand and cancel polynomials:
from IPython.display import display
from scipy import signal
import sympy as sy
sy.init_printing() # LaTeX like pretty printing for IPython
def lti_to_sympy(lsys, symplify=True):
""" Convert Scipy's LTI instance to Sympy expression """
s = sy.Symbol('s')
G = sy.Poly(lsys.num, s) / sy.Poly(lsys.den, s)
return sy.simplify(G) if symplify else G
def sympy_to_lti(xpr, s=sy.Symbol('s')):
""" Convert Sympy transfer function polynomial to Scipy LTI """
num, den = sy.simplify(xpr).as_numer_denom() # expressions
p_num_den = sy.poly(num, s), sy.poly(den, s) # polynomials
c_num_den = [sy.expand(p).all_coeffs() for p in p_num_den] # coefficients
l_num, l_den = [sy.lambdify((), c)() for c in c_num_den] # convert to floats
return signal.lti(l_num, l_den)
pG, pH, pGH, pIGH = sy.symbols("G, H, GH, IGH") # only needed for displaying
# Sample systems:
lti_G = signal.lti([1], [1, 2])
lti_H = signal.lti([2], [1, 0, 3])
# convert to Sympy:
Gs, Hs = lti_to_sympy(lti_G), lti_to_sympy(lti_H)
print("Converted LTI expressions:")
display(sy.Eq(pG, Gs))
display(sy.Eq(pH, Hs))
print("Multiplying Systems:")
GHs = sy.simplify(Gs*Hs).expand() # make sure polynomials are canceled and expanded
display(sy.Eq(pGH, GHs))
print("Closing the loop:")
IGHs = sy.simplify(GHs / (1+GHs)).expand()
display(sy.Eq(pIGH, IGHs))
print("Back to LTI:")
lti_IGH = sympy_to_lti(IGHs)
print(lti_IGH)
The output is:
Depending on your definition of "easy", you should consider deriving your own class from lti, implementing the necessary algebraic operations on your transfer functions. This is probably the most elegant approach.
Here's my take on the subject:
from __future__ import division
from scipy.signal.ltisys import TransferFunction as TransFun
from numpy import polymul,polyadd
class ltimul(TransFun):
def __neg__(self):
return ltimul(-self.num,self.den)
def __floordiv__(self,other):
# can't make sense of integer division right now
return NotImplemented
def __mul__(self,other):
if type(other) in [int, float]:
return ltimul(self.num*other,self.den)
elif type(other) in [TransFun, ltimul]:
numer = polymul(self.num,other.num)
denom = polymul(self.den,other.den)
return ltimul(numer,denom)
def __truediv__(self,other):
if type(other) in [int, float]:
return ltimul(self.num,self.den*other)
if type(other) in [TransFun, ltimul]:
numer = polymul(self.num,other.den)
denom = polymul(self.den,other.num)
return ltimul(numer,denom)
def __rtruediv__(self,other):
if type(other) in [int, float]:
return ltimul(other*self.den,self.num)
if type(other) in [TransFun, ltimul]:
numer = polymul(self.den,other.num)
denom = polymul(self.num,other.den)
return ltimul(numer,denom)
def __add__(self,other):
if type(other) in [int, float]:
return ltimul(polyadd(self.num,self.den*other),self.den)
if type(other) in [TransFun, type(self)]:
numer = polyadd(polymul(self.num,other.den),polymul(self.den,other.num))
denom = polymul(self.den,other.den)
return ltimul(numer,denom)
def __sub__(self,other):
if type(other) in [int, float]:
return ltimul(polyadd(self.num,-self.den*other),self.den)
if type(other) in [TransFun, type(self)]:
numer = polyadd(polymul(self.num,other.den),-polymul(self.den,other.num))
denom = polymul(self.den,other.den)
return ltimul(numer,denom)
def __rsub__(self,other):
if type(other) in [int, float]:
return ltimul(polyadd(-self.num,self.den*other),self.den)
if type(other) in [TransFun, type(self)]:
numer = polyadd(polymul(other.num,self.den),-polymul(other.den,self.num))
denom = polymul(self.den,other.den)
return ltimul(numer,denom)
# sheer laziness: symmetric behaviour for commutative operators
__rmul__ = __mul__
__radd__ = __add__
This defines the ltimul class, which is lti plus addition, multiplication, division, subtraction, and negation; binary ones also defined for integers and floats as partners.
I tested it for the example of Dietrich:
G_s = ltimul([1], [1, 2])
H_s = ltimul([2], [1, 0, 3])
print(G_s*H_s)
print(G_s*H_s/(1+G_s*H_s))
While GH is nicely equal to
ltimul(
array([ 2.]),
array([ 1., 2., 3., 6.])
)
the final result for GH/(1+GH) is less pretty:
ltimul(
array([ 2., 4., 6., 12.]),
array([ 1., 4., 10., 26., 37., 42., 48.])
)
Since I'm not very familiar with transfer functions, I'm not sure how likely it is that this gives the same result as the sympy-based solution due to some simplifications missing from this one. I find it suspicious that already lti behaves unexpectedly: lti([1,2],[1,2]) doesn't simplify its arguments, even though I'd suspect this function to be constant 1. So I'd rather not guess the correctness of this final result.
Anyway, the main message is inheritance itself, so possible bugs in the above implementation hopefully pose only a minor inconvenience. I'm also quite unfamiliar with class definitions, so it's possible that I didn't follow best practices in the above.
I eventually rewrote the above after #ochurlaud pointed out, that my original only worked for Python 2. The reason is that the / operation is implemented by __div__/__rdiv__ in Python 2 (and is the ambiguous "classical division"). In Python 3, however, there is a distinction between / (true division) and // (floor division), and they call __truediv__ and __floordiv__ (and their "right" counterparts), respectively. The __future__ import first in the line of the above code triggers the proper Python 3 behaviour even on Python 2, so the above works on both Python versions. Since floor (integer) division doesn't make much sense for our class, we explicitly signal that it can't do anything with // (unless the other operand implements it).
One could also easily define the respective __iadd__, __idiv__ etc. in-place operations for +=, /= etc., respectively.
I have a list of variables, and a function object and I would like to assign the correct number of variable depending on the function.
def sum2(x,y):
return x + y
def sum3(x,y,z):
return x + y + z
varList = [1,2,3]
so if f = sum2 , I would like it to call first 2 elements of varList, and if f = sum3 , to call it with 3 elements of the function.
This can be done in a single function, if you are always returning the sum of all the passed arguments.
def sum1(*args):
return sum(args)
This is just utilizing positional arguments, as you don't appear to need to explicitly set individual values. It is also most flexible than the solution provided by ZdaR, as you don't need to know ahead of time the maximum number of arguments you can receive.
Some examples:
>>> print sum1(1, 2, 3)
6
>>> print sum1(1)
1
>>> print sum1(-1, 0, 6, 10)
15
Use the inspect module as follows:
import inspect
n2 = len(inspect.getargspec(sum2)[0])
n3 = len(inspect.getargspec(sum3)[0])
sum2(*varList[0:n2])
sum3(*varList[0:n3])
getargspec returns a 4-tuple of (args, varargs, keywords, defaults). So the above code works if all your args are explicit, i.e. not * or ** args. If you have some of those, change the code accordingly.
You may use default initialization, You should keep in mind the maximum number of variables that could be passed to this function. Then create a function with that number of parameters but initializing them with 0, because a+0 = a(in case some parameters are missing it will replace then with 0 which won't affect the results.)
def sum1(a=0, b=0, c=0, d=0):
return a+b+c+d
print sum1(1)
>>> 1
print sum1(1, 2)
>>> 3
print sum1(1, 2, 3)
>>> 6
print sum1(1, 2, 3, 4)
>>> 10
However, if you call the function with more than 4 arguments, it would raise error statement
Also as suggested by #CoryKramer in the comments you can also pass your varlist = [1, 2, 3, 4] as a parameter :
print sum1(*varlist)
>>> 10
Keeping in mind that the len(varlist) should be less than the number of parameters defined.
A general solution:
To get the number of argument, you can use f.func_code.co_argcount and than pass the correct elements from the list:
def sum2(x,y):
return x + y
def sum3(x,y,z):
return x + y + z
varlist = [2,5,4]
[f(*varlist[:f.func_code.co_argcount]) for f in [sum2,sum3]]
>> [7, 11]
You can check if f is a function with the is keyword
def sum2(x, y):
return x + y
def sum3(x, y, z):
return x + y + z
varList = [1, 2, 3]
f = sum2
if f is sum2:
sum = f(varList[0], varList[1])
print('Sum 2: ' + str(sum))
# Prints: 'Sum 2: 3'
f = sum3
if f is sum3:
sum = f(varList[0], varList[1], varList[2])
print('Sum 3: ' + str(sum))
# Prints: 'Sum 3: 6'
A dict of functions:
def two(l):
return l[0] + l[1]
def three(l):
return l[0] * l[1] + l[2]
funcs = {2:two, 3:three}
l = [1, 2, 3]
print len(l)
print funcs[len(l)](l)
What is the best way of implementing an efficient Vector / Point class (or even better: is there one already), that can be used both in Python 2.7+ and 3.x?
I've found the blender-mathutils, but they seem to only support Python 3.x. Then there's this Vector class, that uses numpy, but it's only a 3D vector. Using a list for a Vector like kivy's vector class (sourcecode) that has static attributes (x and y) seems weird too. (There are all these list-methods.)
At the moment I'm using a class that extends namedtuple (as you can see below), but this has the disadvantage of not being able to change the coordinates. I think this can become a performance problem, when thousands of objects are moving and a new (vector) tuple is created everytime. (right?)
class Vector2D(namedtuple('Vector2D', ('x', 'y'))):
__slots__ = ()
def __abs__(self):
return type(self)(abs(self.x), abs(self.y))
def __int__(self):
return type(self)(int(self.x), int(self.y))
def __add__(self, other):
return type(self)(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return type(self)(self.x - other.x, self.y - other.y)
def __mul__(self, other):
return type(self)(self.x * other, self.y * other)
def __div__(self, other):
return type(self)(self.x / other, self.y / other)
def dot_product(self, other):
return self.x * other.x + self.y * other.y
def distance_to(self, other):
""" uses the Euclidean norm to calculate the distance """
return hypot((self.x - other.x), (self.y - other.y))
Edit: I did some testing and it seems that using numpy.array or numpy.ndarray as a vector is too slow. (For example getting an item takes almost twice as long, not to mention creating an array. I think it's more optimized for doing calculations on a large number of items.)
So, I'm looking more for a lightweight vector class with a fixed number of fields (in my case just x and y) that can be used for games. (I don't want to re-invent the wheel if there's already a well-tested one.)
Yeah, there is a vector class: it's in the de facto standard NumPy module. You create vectors like so:
>>> v = numpy.array([1, 10, 123])
>>> 2*v
array([ 2, 20, 246])
>>> u = numpy.array([1, 1, 1])
>>> v-u
array([ 0, 9, 122])
NumPy is very rich and gives you access to fast array operations: dot product (numpy.dot()), norm (numpy.linalg.norm()), etc.
The vector class in numpy in terms of linear algebra would probably be the numpy.matrix which is a subclass of numpy.ndarray. It's not cleaner per se but it makes your code cleaner because algebraic operations are assumed instead of elementwise.
In [77]: a = np.array([1,2])
In [78]: b = np.array([3,3])
In [79]: a*b
Out[79]: array([3, 6])
In [80]: np.dot(a,b)
Out[80]: 9
In [81]: np.outer(a,b)
Out[81]:
array([[3, 3],
[6, 6]])
In [82]: a = np.matrix(a).T
In [83]: b = np.matrix(b)
In [84]: b*a
Out[84]: matrix([[9]])
In [85]: a*b
Out[85]:
matrix([[3, 3],
[6, 6]])
If you want to create your own, base it on one of these, for example:
class v2d(np.ndarray):
def __abs__(self):
return np.linalg.norm(self)
def dist(self,other):
return np.linalg.norm(self-other)
def dot(self, other):
return np.dot(self, other)
# and so on
Which in the simplest case you can just make by viewing an ndarray as your new class:
In [63]: a = np.array([1,2]).view(v2d)
In [64]: b = np.array([3,3]).view(v2d)
In [65]: a
Out[65]: v2d([1, 2])
In [66]: abs(b)
Out[66]: 4.2426406871192848
In [67]: a - b
Out[67]: v2d([-2, -1])
In [68]: a*b
Out[68]: v2d([3, 6])
In [69]: a*3
Out[69]: v2d([3, 6])
In [70]: a.dist(b)
Out[70]: 2.2360679774997898
In [71]: b.dist(a)
Out[71]: 2.2360679774997898
In [72]: a.dot(b)
Out[72]: 9
Here is more information on subclassing the ndarray.
I needed a quick solution as well so I just wrapped numpy's array into my own. You'll notice some design decisions which can be changed to fit your own needs (like defaults).
If you'd like to use it: https://gist.github.com/eigencoder/c029d7557e1f0828aec5
import numpy as np
class Point(np.ndarray):
"""
n-dimensional point used for locations.
inherits +, -, * (as dot-product)
> p1 = Point([1, 2])
> p2 = Point([4, 5])
> p1 + p2
Point([5, 7])
See ``test()`` for more usage.
"""
def __new__(cls, input_array=(0, 0)):
"""
:param cls:
:param input_array: Defaults to 2d origin
"""
obj = np.asarray(input_array).view(cls)
return obj
#property
def x(self):
return self[0]
#property
def y(self):
return self[1]
#property
def z(self):
"""
:return: 3rd dimension element. 0 if not defined
"""
try:
return self[2]
except IndexError:
return 0
def __eq__(self, other):
return np.array_equal(self, other)
def __ne__(self, other):
return not np.array_equal(self, other)
def __iter__(self):
for x in np.nditer(self):
yield x.item()
def dist(self, other):
"""
Both points must have the same dimensions
:return: Euclidean distance
"""
return np.linalg.norm(self - other)
def test():
v1 = Point([1, 2, 3])
v2 = Point([4, 5, 7])
v3 = Point([4, ])
sum12 = Point([5, 7, 10])
dot12 = Point([4, 10, 21])
# Access
assert v2.x == 4
assert v2.y == 5
assert v2.z == 7
assert v3.z == 0
assert Point().x == 0
assert v2[0] == 4
assert v1[-1] == 3 # Not needed but inherited
assert [x for x in v2] == [4, 5, 7], "Iteration should return all elements"
# Operations
assert v1 + v2 == sum12
assert v1 * v2 == dot12
assert v1.dist(v2) ** 2 == 34
assert v1 != v2
assert v2.size == 3, "v2 should be a 3d point"
print "pass"
if __name__ == "__main__":
test()