Class polynomial - python

I am learning classes in Python, I created a class called polynomial, and am trying to add two polynomials, but always get the following error message
soma.termos[i] = self[i] + other[i] TypeError: 'Polinomio' object
does not support indexing to fix
to fix I created an attribute that is the size of the vector and creates a vector of zeros of size n, but still, the error persists, what is wrong?
class Polinomio:
def __init__ (self, termos = [], n = 0):
self.termos = termos
self.n = [0] * n
def __len__ (self):
return len(self.termos)
def __setitem__ (self, i, x):
self.termos[i] = x
def __add__ (self, other):
soma = Polinomio(n = len(self.termos))
for i in range(len(self.termos)):
soma.termos[i] = self[i] + other[i]
def print (self):
print(self.termos)
p1 = Polinomio([1, 2, 3])
p2 = Polinomio([1, 2, 3])
p2.print()
p3 = Polinomio()
p3 = p1 + p2

You're not using your internal termos property when adding, instead you're trying to index your whole instance which, unsurprisingly, raises an error. Try changing your __add__ method to:
def __add__ (self, other):
soma = Polinomio(n = len(self.termos))
for i in range(len(self.termos)):
soma.termos[i] = self.termos[i] + other[i]
return soma
Or even better:
def __add__ (self, other):
soma = Polinomio(n = len(self.termos))
for i, v in enumerate(self.termos):
soma.termos[i] = v + other[i]
return soma
Also, do not initialize your termos list in your __init__ signature as it will always refer to the same list. Instead, declare it as None and build it as new whenever it's not passed, i.e.:
def __init__ (self, termos = None, n = 0):
self.termos = termos or []
self.n = [0] * n

You should add a method __getitem__:
def __getitem__(self, i):
return self.termos[i]
And also in your __add__ function, you instantiate a Polinomio by saying n = len(self.termos) but your using something called keyword arguments, so it will not actually instantiate a Polinomio with n as len(self.termos, you should instead say Polinomio([], len(self.termos) or implement keyword arguments if you want to use that syntax to intstantiate it.

Related

Getting a type error while using fori_loop with JAX

I'm developing a code using JAX, and I wanted to JIT some parts of that had big loops. I didn't want the code to be unrolled so I used fori_loop, but I'm getting an error and can't figure out what I am doing wrong.
The error is:
self.arr = self.arr.reshape(new_shape+new_shape)
TypeError: 'aval_method' object is not callable
I was able to reduce the code to the following:
import jax.numpy as jnp
import jax
class UB():
def __init__(self, arr, new_shape):
self.arr = arr
self.shape = new_shape
if type(arr) is not object:
self.arr = self.arr.reshape(new_shape+new_shape)
def _tree_flatten(self):
children = (self.arr,) # arrays / dynamic values
aux_data = {
'new_shape': self.shape
} # static values
return (children, aux_data)
#classmethod
def _tree_unflatten(cls, aux_data, children):
return cls(*children, **aux_data)
class UM():
def __init__(self, arr, r=None):
self.arr = arr
self.r = tuple(r)
def _tree_flatten(self):
children = (self.arr,) # arrays / dynamic values
aux_data = {
'r': self.r
} # static values
return (children, aux_data)
#classmethod
def _tree_unflatten(cls, aux_data, children):
return cls(*children, **aux_data)
for C in [UB, UM]:
jax.tree_util.register_pytree_node(
C,
C._tree_flatten,
C._tree_unflatten,
)
def s_w(ub, ums):
e = jnp.identity(2)
u = UM(e, [2])
ums[0] = u
return ub, ums
def s_c(t, uns):
n = 20
ums = []
for un in uns:
ums.append(UM(un, [2]))
tub = UB(t.arr, t.r)
s_loop_body = lambda i,x: s_w( ub=x[0], ums=x[1])
tub, ums = jax.lax.fori_loop(0, n, s_loop_body, (tub, ums))
# for i in range(n):
# tub, ums = s_loop_body(i, (tub, ums))
return jnp.array([u.arr.flatten() for u in ums])
uns = jnp.array([jnp.array([1, 2, 3, 4]) for _ in range(6)])
t = UM(jnp.array([1, 0, 0, 1]), r=[2])
uns = s_c(t, uns)
Has anyone encountered this issue or can explain how to fix it?
The issue is discussed here: https://jax.readthedocs.io/en/latest/pytrees.html#custom-pytrees-and-initialization
Namely, in JAX pytrees are used as general containers, and are sometimes initialized with abstract values or other place-holders, and so you cannot assume that arguments to a custom PyTree will be of array type. You might account for this by doing something like the following:
class UB():
def __init__(self, arr, new_shape):
self.arr = arr
self.shape = new_shape
if isinstance(arr, jnp.ndarray):
self.arr = self.arr.reshape(new_shape+new_shape)
When I run your code with this modification, it gets past the error you asked about, but unfortunately does trigger another error due to the body function of the fori_loop not having a valid signature (namely, the arr attributes of the ums have different shapes on input and output, which is not supported by fori_loop).
Hopefully this gets you on the path toward working code!

Python function call in class

I would like to make a class that returns a pseudo random number generator. I want to save the result of the _rand function in _r but when I call the function _rand(int(time.time())) I get the error message "rand() missing 1 required positional argument: 'seed'". Could someone please explain me what I did wrong.
class PRNG:
import time
_m = 32768
_b = 9757
_c = 6925
def _rand(self, seed):
n = seed % self._m
while True:
n = (n * self._b + self._c) % self._m
yield n
_r = _rand(int(time.time()))
def rand(self) :
return self._r.__next__()
prng = PRNG()
print(prng.rand())
_rand() takes two arguments; self and seed. Specifically you need to provide what instance the method is being called on. Instead of what you have, try defining _r in a constructor
def __init__(self):
self._m = 32768
self._b = 9757
self._c = 6925
self._r = self._rand(int(time.time()))

Name "function name" is not defined

I've been attempting to complete one of my subjects for the OOP, but I couldn't manage to figure out what's wrong with the definition of my functions. I'm a newbie in this language, already searched the forums but I couldn't find anything useful.
Error message:
Traceback (most recent call last):
File "/home/main.py", line 44, in
add(x, y)
NameError: name 'add' is not defined
This is the program I wrote.
class Complex(object):
def __init__(self, r = 0, i = 0):
self.r = r
self.i = i
def __str__ (self):
return "%s + i%s" % (self.r, self.i)
def add (self, other):
summ = Complex()
summ.r = self.r + other.r
summ.i = self.i + other.i
return "Sum is %d" % summ
def dif (self, other):
dif = Complex()
dif.r = self.r - other.r
dif.i = self.i - other.i
return dif
def multiply (self, other):
multiply = Complex()
multiply.r = self.r * other.r
multiply.i = self.i * other.i
return "%d" % (-1 * multiply.r * multiply.i)
def divide (self, other):
divide = Complex()
divide.r = self.r / other.r
divide.i = self.i / other.i
return "%d" % (divide.r / divide.i)
x = Complex()
y = Complex()
x.r = int(input("Type in real part of x: \n"))
x.i = int(input("Type in imaginary of x: \n"))
print (x, "\n")
y.r = int(input("Type in real part of y: \n"))
y.i = int(input("Type in imaginary of y: \n"))
print (y, "\n")
add(x, y)
The add() function is a member of the Complex class but you are calling it on its own.
You need to call it like this
x.add(y)
When a function is a member of a class like below:
class Complex(object):
def add (self, other):
# Do stuff
The object the function is called on automatically gets passed as self.
So if you call x.add(y), self will be x and other will be y.
If add is a method of your class Complex, then you must write x.add(y) instead of add(x, y).
I know that it is confusing in Python. You need always to apply the "self" as first argument of a method, although it is not an argument, but the object whose method you call.

Delayed Compute with Method Chaining in Python

Let say I have a class:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
def add(self, value):
# Add amount 'value' to every element in the results list
def minus(self, value):
# Subtract amount 'value' from every element in the results list
def compute(self):
# Perform computation
Is there a way to do something like:
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
m.compute() # This would actually run the computations in order
How do I do something like this in python?
Personally, I would have .add(), et al, push the operator and the operand onto a list and then have .compute() walk through the list, computing the answer as it goes.
Operator chaining is easily accomplished by having each operator return self as its final instruction.
For example:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
self.operations = []
def add(self, value):
# Add amount 'value' to every element in the results list
self.operations.append(('+', value))
return self
def minus(self, value):
# Subtract amount 'value' from every element in the results list
self.operations.append(('-', value))
return self
def compute(self):
results = []
for x in self.results:
for op, value in self.operations:
if op == '+':
x += value
elif op == '-':
x -= value
results.append(x)
return results
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
print(m.compute()) # This would actually run the computations in order
Wow, you guys are fast!
Here is another go also with a stack, but manipulating the results-list:
class MATH(object):
def __init__(self):
self.results = [0, 1, 2]
self.stack = []
def add(self, value):
self.stack.append(value)
return self
def minus(self, value):
self.stack.append(-value)
return self
def compute(self):
for s in self.stack:
for index, _ in enumerate(self.results):
self.results[index] += s
m = MATH()
m.add(5).minus(2).add(7) # This would be a lazy and not actually compute
m.compute() # This would actually run the computations in order
print m.results
[10, 11, 12]
As #Rob pointed out, you will need some way to store the operators so that the final compute method can be utilized correctly. This solution uses __add__ and __sub__, with a decorator to store the operators. Note, however, that it would be much more efficient to keep a running total of the values that have been pushed to the stack:
import operator as op
from collections import deque
def operator(f):
def wrapper(cls, _):
cls.operators.append(f.__name__.replace('__', ''))
return f(cls, _)
return wrapper
class Math:
def __init__(self):
self.stack = []
self.operators = deque()
#operator
def __sub__(self, _val):
self.stack.append(_val)
return self
#operator
def __add__(self, _val):
self.stack.append(_val)
return self
def compute(self):
_result = 0
while self.stack:
a, *c = self.stack
_result = getattr(op, self.operators.popleft())(_result, a)
self.stack = c
return _result
m = Math()
m1 = m + 5 - 2 + 7
print([m1.stack, m1.operators])
print(m1.compute())
Output:
[[5, 2, 7], ['add', 'sub', 'add']]
10
Here's a string-based approach which requires little brainpower.
class Math:
def __init__(self):
self.stack = '0'
#staticmethod
def wrap(expr):
return '(' + expr + ')'
def _op(self, other, op):
self.stack = ' '.join([Math.wrap(self.stack), op, str(other)])
def add(self, other):
self._op(other, '+')
return self
def mul(self, other):
self._op(other, '*')
return self
def compute(self):
return eval(self.stack)
m = Math()
print(m.add(2).mul(3).compute())

Obtaining values from dictionary in OOP: "AttributeError"

I am trying to get values from my dictionary VALUES. My program creates combination of possible positions and gets the last position. Then I want to get the value. Everything works well here except indicated .get_value method. When I execute this code I receive:
AttributeError: 'Combination' object has no attribute 'get_value'
Theoretically it should be easy but I am new to OOP and I don't see what is wrong here.
X = ['A','B','C']
Y = ['1','2','3']
VALUES = {'A':10, 'B': 50, 'C':-20}
class Combination:
def __init__(self,x,y):
if (x in X) and (y in Y):
self.x = x
self.y = y
else:
print "WRONG!!"
def __repr__ (self):
return self.x+self.y
def get_x(self):
return self.x
def get_y(self):
return self.y
class Position:
def __init__(self):
self.xy = []
for i in X:
for j in Y:
self.xy.append(Combination(i,j))
def choose_last(self):
return self.xy.pop()
def __str__(self):
return "List contains: " + str(self.xy)
class Operation1:
def __init__(self):
self.operation1 = []
def __str__(self):
s = str(self.operation1)
return s
def get_value(self):
V = VALUES.get(self)
return V
pos = Position()
print pos
last_item = pos.choose_last()
print "Last item:", last_item, pos
last_value = last_item.get_value() # <---- Here is a problem
How can I obtain value of my position? Value is determined by the X value - this is A,B or C. In the dictionary I have a numeral value for the letter.
You are appending objects of Combination into xy of Position. When you say choose_last, it will return the last Combination object inserted into xy. And you are trying to invoke get_value method on a Combination object, which doesnt have that method. Thats why you are getting that error.
Always use new style classes.

Categories