How to manipulate expressions in matrices using sympy? - python

I'm writing a library, and I can construct expressions using objects from my library. For example, x and y are instances from my library, and I can construct expressions like:
# below is a simplified version of my class
class MySymbol(object):
import random
_random_value = random.randint(1,4)
def __init__(self, value):
self.value = value
def __add__(self, symbol):
return MySymbol(self.value + symbol.value)
def __mul__(self, symbol):
return MySymbol(self.value * symbol.value)
def __repr__(self):
return str(self.value)
def _get_random_value(self):
return self._random_value
x,y = sympy.symbols('x y')
x = MySymbol(9)
y = MySymbol(3)
import sympy
A = sympy.Matrix([[x,y],[x,y]])
B = sympy.Matrix([[x+y,x*y]])
This is also true for matrix operations. The sympy.Matrix class converts these elements to sympy.core.numbers.Integer, when I want them to maintain their type MySymbol:
BA=B*A
print type(BA[0,0])
print type(x*x+y*x+x*x*y) # first element of matrix in *symbolic* form
<class 'sympy.core.numbers.Integer'>
<class '__main__.MySymbol'>
Now, because BA[0,0] is not of type MySymbol anymore, I cannot call the methods I want on it:
BA[0,0]._get_random_value() # DOES NOT WORK
>> AttributeError: 'Integer' object has no attribute '_get_random_value'
expression = x*x+y*x+x*x*y
expression._get_random_value() # THIS DOES WORK
>> 4
How do I take advantage of matrix multiplication from sympy.Matrix, but yet still allow the elements of the matrix to retain their class type of MySymbol? and still allow all of their methods (such as _get_random_value()) to be accessible?

You need to subclass from a SymPy class to use it within SymPy. Depending on what your class is doing will tell you what class to subclass, but the most typical superclass is Expr. See my answer to a very similar question here.

Related

Best practice for defining a class that computes attributes in order when initialized

I would like to define a class that does something like:
Class computer():
def __init__(self, x):
# compute first the 'helper' properties
self.prop1 = self.compute_prop1(x)
self.prop2 = self.compute_prop2(x)
# then compute the property that depends on 'helpers'
self.prop3 = self.compute_prop3(x)
def compute_prop1(self, x):
return x
def compute_prop2(self, x):
return x*x
def compute_prop3(self, x):
return self.prop1 + self.prop2
Then, when I initialize an instance, I get all properties computed in order (first helpers, then everything depending on helpers later):
>>> computer = Computer(3)
>>> computer.__dict__
{'prop1': 3, 'prop2': 9, 'prop3': 12}
However, I think there is a better practice of writing this code, for example using decorators. Could you please give me some hints? Thank you!
Here's your class using properties instead (with an added method for returning each property):
Class PropertyComputer:
def __init__(self, x):
self._x = x
#property
def prop1(self):
return self._x
#property
def prop2(self):
return self._x * self._x
#property
def prop3(self):
return self.prop1 + self.prop2
def get_props(self):
return self.prop1, self.prop2, self.prop3
Design-wise, I believe this is better because:
storing x as an instance variable makes more sense: the point of using objects is to avoid having to pass variables around, especially those that the object itself can keep track of;
the attribute assignment and its corresponding calculation are bundled together in each property-decorated method: we'll never have to think whether the problem is in the init method (where you define the attribute) or in the compute method (where the logic for the attribute's calculation is laid out).
Note that the concept of "first calculate helpers, then the properties depending on them" does not really apply to this code: we only need to evaluate prop3 if/when we actually need it. If we never access it, we never need to compute it.
A "bad" side-effect of using properties, compared to your example, is that these properties are not "stored" anywhere (hence why I added the last method):
c = PropertyComputer(x=2)
c.__dict__ # outputs {'_x': 2}
Also note that, using decorators, the attributes are calculated on-the-fly whenever you access them, instead of just once in the init method. In this manner, property-decorated methods work like methods, but are accessed like attributes (it's the whole point of using them):
c = PropertyComputer(x=2)
c.prop1 # outputs 2
c._x = 10
c.prop1 # outputs 10
As a side note, you can use functools.cached_property to cache the evaluation of one of these properties, in case it's computationally expensive.
I think the following would be the easiest way to avoid redundancy
class computer():
def __init__(self, x):
self.prop_dict = self.compute_prop_dict(x)
def compute_prop_dict(self, x):
prop1 = x
prop2 = x*x
return {'prop1': prop1, 'prop2': prop2, 'prop3': prop1 + prop2}
So anything that would come after instantiation could have access to these helpers via the prop_dict
But as said by Brian as a comment this order is just a language specification for Python 3.7

Error in returning list for repr()

I have a class 'mn_board()' that creates a m x n matrix as follows:
class mn_board(object):
cell_char = 'O'
def __init__(self, r, c):
self.r = r
self.c = c
def __repr__(self):
columns = [[self.cell_char]*self.c]
rows = [columns*self.r]
return rows
my_board = mn_board(4,5)
print my_board
However, it shows the following error:
TypeError: __str__ returned non-string (type list)
I am aware that the above should code displays only the list form and not the board form, that's not the problem I am facing as the list can easily be then converted into a matrix format.
Are lists not returnable in a repr() function? Any clarification?
Repr is basically to return the value of type string in a printable representation. From your code it is returning of type list so got the error. Now try to convert using str() by return str(rows)
You can find more description at **https://docs.python.org/3/library/functions.html#repr or **https://docs.python.org/3/reference/datamodel.html#object.repr
Change the code to :
class mn_board(object):
cell_char = 'O'
def __init__(self, r, c):
self.r = r
self.c = c
def __repr__(self):
columns = [[self.cell_char]*self.c]
rows = [columns*self.r]
return str(rows)
my_board = mn_board(4,5)
print my_board
From the documentation (emphasis mine):
object.__repr__(self)
Called by the repr() built-in function and by
string conversions (reverse quotes) to compute the “official” string
representation of an object. If at all possible, this should look like
a valid Python expression that could be used to recreate an object
with the same value (given an appropriate environment). If this is not
possible, a string of the form <...some useful description...> should
be returned. The return value must be a string object. If a class
defines __repr__() but not __str__(), then __repr__() is also used
when an “informal” string representation of instances of that class is
required.

When creating a wrapper class in python, how do I get the superclass's methods to return an instance of my wrapper class

For example if I create a simple wrapper around a pandas dataframe:
from pandas import DataFrame
class MyDataFrame(DataFrame):
def __init__(self,data):
DataFrame.__init__(self,data)
#staticmethod
def add(a, b):
return a + b
and then I instantiate it..
x = MyDataFrame([1,2,3])
x.add(1,2)
# => 3
type(x)
# => __main__.MyDataFrame
it works. But, if I call a a dataframe method on it that returns a dataframe, It is no loger an instance of my wrapper class.
y = x.reindex([3,4,5])
type(y)
# => pandas.core.frame.DataFrame
How do I get it to return an instance of MyDataFrame for all DataFrame methods? Is this a common issue? Am I approaching this in the wrong way?
The example you have shown is not a wrapper but a subclass in Python. Now python subclasses and method resolution in your case behave by simple rules
Look at the type of the receiver object of the method.
Check the class hierarchy of the class and find the first instance the method is defined. Then look at the signature of that method and execute it accordingly. In your case, class hierarchy is simple subclass-superclass.
So, in your case,
x is defined as an object of class MyDataFrame -- simple. Obviously, type(x) is MyDataFrame, by definition.
During call of add, it looks at receiver object, which is x of class MyDataFrame. And this class in fact defines the method add. So, it simply returns the result of that method, Curiously, try calling DataFrame([1, 2, 3]).add(1, 2). The result will be different since it looks at the add method as defined in pandas.DataFrame class.
Now comes the third part - Let's apply same reasoning. reindex is not defined in MyDataFrame. Where should we look next? Class hierarchy, that means pandas.DataFrame. Now reindex is indeed defined by this class and it returns a pandas.DataFrame object!. (See this: http://pandas.pydata.org/pandas-docs/dev/generated/pandas.DataFrame.reindex.html#pandas.DataFrame.reindex) So, no wonder y is a pandas DataFrame.
Now I don't understand what you are doing by extending a pandas DataFrame in first place. Extending like this is not a common practice. If you provide details of what you want to do, maybe we can provide a solution.
Edit: Your original question is concerned with extension methods or extension objects (C# has them, and as you rightly pointed out, JS prototypes give you same functionality. Python does not have extension methods/objects as first class members. There has been discussion on that. e.g python extension methods)
There have been several cases in Pandas where the classes have not been implemented well to form the basis for derived classes. Some of these issues are fixed, e.g., https://github.com/pydata/pandas/pull/4271 and https://github.com/pydata/pandas/issues/60 .
It is possible to implement a parent reindex method so the result is a child subclass:
from pandas import DataFrame
class DF():
def __init__(self, data):
print('DF __init__')
self.data = data
def reindex(self, index):
print('DF reindex')
return self.__class__(self.data)
# return DF(self.data) # not like this!
class MyDF(DF):
def __init__(self, data):
DF.__init__(self, data)
#staticmethod
def add(a, b):
return a + b
x = MyDF([1,2,3])
x.add(1,2)
# => 3
type(x)
y = x.reindex([3,4,5])
type(y)
z = DF([1,2,3])
type(z.reindex([1, 2]))
In newer versions of Pandas the `_constructor' is set internally to control the type returned. Setting this class attribute seems to do the trick:
class MyDataFrame(DataFrame):
def __init__(self, *args, **kwargs):
DataFrame.__init__(self, *args, **kwargs)
#staticmethod
def add(a, b):
return a + b
MyDataFrame._constructor = MyDataFrame
>>> type(y)
<class '__main__.MyDataFrame'>

In python, How to make right operand takes the priority (of __rmul__ method) when multiplying two different class?

I am trying to make the following thing work but without success:
I defined my own type Unit (inherit from build-in type float) to implement algebra for quantities with units. It does things in the way that:
class Unit(float):
"""provide a simple unit converter for a given quantity"""
def __new__(cls, unit, num=1.):
return super(Unit, cls).__new__(cls, num)
def __init__(self, unit, num=1.):
"""set up base unit"""
self.unit = unit
def __str__(self,):
return '{:s} {:s}'.format(super(Unit, self).__str__(), self.unit)
def __rmul__(self, other):
print 'rmul: {:f}'.format(super(Unit, self).__rmul__(other))
return Unit(self.unit, super(Unit, self).__rmul__(other))
def to(self,target):
fun_conv = _conv(self.unit, target)
return Unit(target, num=fun_conv(self))
c = 3e8 * Unit('m/s') # this will 1) create a Unit instance with magnitude '1' and unit 'm/s',
# 2) invoke __rmul__ to return a new instance with number 3e8 and unit 'm/s' to variable 'c'
print c.to('km/s') # returns 3e5 km/s
However, this __rmul__ is only invoked when float being the left operand. If I make something like this:
velocities = np.array([20, 10]) * Unit('m/s')
Then Unit.__rmul__ will not be invoked, and the same numpy ndarray is returned since now Unit('m/s') was treated like a plain float with value 1.0
What I expect is: after ndarray * Unit, a function similar to Unit.to can be attacted to the instance of ndarray as a method as well as an attribute unit, so I can further call ndarray.to to return a copy (or modified version, if it could, for memory efficiency) of the original ndarray that associated with new values and unit. How do I proceed?
According what I have known and searched, __mul__ of the left operand will be of the prior during *, i.e., the interpretor checks LO.__mul__() first, if it fails, then goes to RO.__rmul__(). I don't quite want to override numpy.ndarray.__mul__ because I really don't know how complicated it would be, and whether there would be a big mess in case that it breaks the rules that ndarray acting on other objects.
And, actually I even cannot find where are the codes that defines __mul__ for ndarray. I simply used inspect.getsource(np.ndarray) but without success. Why does it fail on this? the exception was barely an IOError.
Thank you so much for your concern!
If you don't inhereit from float, but instead create a new type wrapping float (so float._ mul_(yourtype) does not work), rmul will do what you want. The wrapping will of course not be free, though... and you'll have to implement all operations you want the type to support.
class T(object):
def __init__(self, val):
self.val = val
def __mul__(self, x):
print("mul")
return T(self.val*x)
def __rmul__(self, x):
print("rmul")
return T(self.val*x)
def __repr__(self):
return str(self.val)
>>> t = T(2)
>>> t * 2
mul
4
>>> 2*t
rmul
4

Add to custom class in Python

I would like to be able to add to a custom class in the style of:
x=myclass("Something", 7)
x + 3
7, of course, corresponds with an inner property that I'd like to increment by adding to it.
The class holds a number that refers to a location in a list. This might seem like something that can be done by a normal integer, but I need it to act as a separate type. This is all done to emulate an old game language. The class is its 'variable' class, and the value of the variable is stored in the aforementioned list. Apparently, on older version of the game, arrays were faked by doing math on the variable object instance to grab a different variable. So I'm trying to emulate that.
If you want to support addition for class instances, you need to define an __add__() method on your class:
class MyClass(object):
def __init__(self, x):
self.x = x
def __add__(self, other):
return self.x + other
Example:
>>> a = MyClass(7)
>>> a + 3
10
To also support 3 + a, define the __radd__() method.
If you want to be able to update the x attribute of MyClass instances using
a += 3
you can define __iadd__().
If you want class instances to behave like integers with some additional methods and attributes, you should simply derive from int.
What you're looking to do is operator overloading. You can do this in python new style classes by overloading the __add__ method like so:
>>> class Test(object):
... def __init__(self): self.prop = 3
... def __add__(self, x):
... return self.prop + x
...
>>> Test() + 4
7
>>>

Categories