I created a class of matrix with python:
class MatrixOperation:
...
def create_matrix(self):
some function for creation of matrix.
return matrix
def matrix_vector_multiplication(self, x):
mat = self.create_matrix()
return numpy.dot(mat, x)
And:
M = MatrixOperation(...)
x = some set of vector
for i in range(n):
M.matrix_vector_multiplication(x[i])
The problem is, for each iteration, M.matrix_vector_multiplication(x[i]) will recompute mat = self.create_matrix() before calculating numpy.dot(mat, x), that is unnecessary (since it could be computed once at the beginning). How can I avoid this?
Thanks,
To avoid recreating the matrix each time, create an instance attribute in the class's __init__ method - similar to this.
class Matrix(object):
def __init__(self, data):
self.matrix = self.create_matrix(data)
# or simply
# self.matrix = np.matrix(data)
def create_matrix(data):
# create the_matrix
return the_matrix
def do_something(self, x):
z = some_function(self.matrix, x)
return z
my_matrix = matrix([[1,2,3,4],[4,3,2,1]])
just making a copy of the matrix should fix your problem.
import copy
class MatrixOperation:
matrix = None
...
def create_matrix(self):
if self.matrix is not None:
return copy.copy(self.matrix)
some function for creation of matrix.
self.matrix = matrix
return matrix
def matrix_vector_multiplication(self, x):
mat = self.create_matrix()
return numpy.dot(mat, x)
Related
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!
When I call a class object, I want it to return a list or any other variable other than string
class Vec:
def __init__(self, data) -> None:
self.data = data #THIS IS A LIST
def __str__(self) -> list:
return self.data
a = Vec([0,1,2,3])
print(a)
#TypeError: __str__ returned non-string (type list)
Instead I get a TypeError, if I set the "self.data" to a string it will work
Is there any Magic Method for this? Thanks in advance
here is the full code in case you need to see it all
note: I am not done finishing it yet and my problem is that for example if I want to multiply Mat with a Vec I would have to do Mat * Vec.data or Mat * Vec.T (T stands for transposed) which I dont like and I would just like to type Mat * Vec in case I dont need to transpose the vector. Sorry for my messy code and my bad explanation of my problem
class MatrixMatchError(Exception):
def __init__(self):
self.message = "Matrix sizes do not match"
super().__init__(self.message)
pass
class MatrixRowColError(Exception):
def __init__(self):
self.message = "The number of columns in the first matrix do not equal to the number of rows in the second."
super().__init__(self.message)
pass
class Vec:
def __init__(self, x, identity=1) -> None:
self.x = x
self.data = self.Create(x, 1, identity)
self.T = self.Transpose()
def Create(self, x, y, identity) -> list:
vec = []
for i in range(y):
vec.append([])
for j in range(x):
vec[i].append(identity)
return vec
def Transpose(self) -> list:
vec = self.Create(len(self.data), len(self.data[0]), 0)
for i in range(len(self.data)):
for j in range(len(self.data[0])):
vec[j][i] = self.data[i][j]
return vec
class Mat:
def __init__(self, x, y=0, identity=1) -> None:
self.x = x
if y == 0:
self.y = x
else:
self.y = y
self.data = self.Create(self.x, self.y, identity)
self.T = self.Transpose()
def __add__(self, data):
if not self.CheckSize(data):
raise MatrixMatchError
mat3 = self.data.copy()
for i in range(len(self.data)):
for j in range(len(self.data[0])):
mat3[i][j] = self.data[i][j] + data[i][j]
return mat3
def __sub__(self, data):
if not self.CheckSize(data):
raise MatrixMatchError
mat3 = self.data.copy()
for i in range(len(self.data)):
for j in range(len(self.data[0])):
mat3[i][j] = self.data[i][j] - data[i][j]
return mat3
def __mul__(self, data):
if not self.CheckRowCol(data):
raise MatrixRowColError
mat3 = self.Create(len(data[0]), len(self.data), 0)
for i in range(len(self.data)):
for j in range(len(data[0])):
for k in range(len(self.data[0])):
mat3[i][j] += self.data[i][k] * data[k][j]
return mat3
def Create(self, x, y, identity) -> list:
mat = []
for i in range(y):
mat.append([])
for j in range(x):
mat[i].append(0)
if x == y:
for i in range(x):
mat[i][i] = identity
return mat
def Transpose(self) -> list:
mat = self.Create(len(self.data), len(self.data[0]), 0)
for i in range(len(self.data)):
for j in range(len(self.data[0])):
mat[j][i] = self.data[i][j]
return mat
def CheckSize(self, data):
if len(self.data) != len(data) or len(self.data[0]) != len(data[0]):
return False
return True
def CheckRowCol(self, data):
if len(data) != len(self.data[0]):
return False
return True
def Transform(self):
pass
def Scale(self):
pass
def Rotate(self):
pass
mat1 = Mat(2)
mat1.data = [[4,5, 4],
[9,3, 7],
[7,1, 3]]
vec = Vec(3)
print(mat1 * vec.T)
The builtin str() function will raise a TypeError if it calls your __str__ and gets something that isn't a string, and you won't convince it to do otherwise.
What you probably want is for Vec.__str__ to return the string representation of data, rather than data itself:
class Vec:
def __init__(self, data: list) -> None:
self.data = data
def __str__(self) -> str:
return str(self.data)
The __str__ method has no bearing on your other use case:
for example if I want to multiply Mat with a Vec I would have to do Mat * Vec.data or Mat * Vec.T (T stands for transposed) which I dont like and I would just like to type Mat * Vec in case I dont need to transpose the vector.
This should instead be addressed in Mat.__mul__ (which should operate on a Vec, not the underlying list) and Vec.T/Vec.Transpose (which should return a Vec, not a list):
class Vec:
...
def Transpose(self) -> 'Vec':
vec = self.Create(len(self.data), len(self.data[0]), 0)
for i in range(len(self.data)):
for j in range(len(self.data[0])):
vec[j][i] = self.data[i][j]
return Vec(vec)
class Mat:
...
def __mul__(self, vec: Vec) -> list[list[int]]:
if not self.CheckRowCol(vec.data):
raise MatrixRowColError
mat3 = self.Create(len(vec.data[0]), len(self.data), 0)
for i in range(len(self.data)):
for j in range(len(vec.data[0])):
for k in range(len(self.data[0])):
mat3[i][j] += self.data[i][k] * vec.data[k][j]
return mat3
Now you can indeed do Mat * Vec or Mat * Vec.T and it will do the right thing.
Note that it would probably be better for Mat.__mul__ to return a Mat, but you haven't provided a constructor that makes it easy for me to implement that part -- nevertheless I hope this gives you a better way to think about your class interfaces and how they can make it easier (or harder) to use the class! Ideally the user of the class shouldn't even be able to access the internals, much less be forced to.
Unrelated to this, I'd suggest spending a bit of time learning about Python's list comprehension syntax, because it'll save you a lot of list allocation boilerplate (i.e. your various Create methods). :)
I have a class method that stops returning a value when I try accessing through an inherited subclass.
Have no idea what's causing it to not return the appropriate value.
Here's what I have:
class KNN():
def __init__(self, neighbors=5, centered=True):
self.neighbors = neighbors
self.centered = centered
def _get_distance(self, xi):
return np.sqrt(((xi - self.X_fit)**2).sum(1))
def fit(self, X, y):
if self.centered:
self.X_fit = standardize(X)
else:
self.X_fit = X
self.y_fit = y
def predict(self, X, centered=False):
m, n = X.shape[0], self.X_fit.shape[0]
self.dist_matrix = np.zeros((m, n))
X_pred = np.zeros(X.shape)
if standardize:
X_pred = standardize(X)
else:
X_pred = X
for row in range(m):
self.dist_matrix[row] = self._get_distance(X_pred[row])
self.idx_vals = np.argsort(self.dist_matrix)[:, :self.neighbors]
self.y_idx = self.y_fit[self.idx_vals]
self.preds = [self.neighbor_calculation(self.y_idx[i]) for i in range(len(self.y_idx))]
return self.preds
If I access the KNN class directly the predict method works as intended, and it returns an array of the predicted values.
However, it stops when I try and create a subclass that inherits from KNN:
class KNNClassifier(KNN):
def predict(self, X, centered=False):
self.neighbor_calculation = majority_vote
super().predict(X, standardize)
When I access the predict method through the KNNClassifier class it doesn't return a value.
However, self.preds contains the actual predictions.
But trying something like KNNClassifier.predict(X)[:10] gives the error message:
'NoneType' object is not subscriptable'
I don't know why the returned value is suddenly being interpreted as None.
You are using super to call the parent method from the child, which is right, but you need to use return to return the value:
return super().predict(X, standardize)
I am trying to define a class within which a function of many variables is optimized. Normally I'm working with ~500-1000 variables. In this class, I need to pass function and its derivative to minimize in scipy to find the x0 which minimizes this function.
The following is a simple working example of the concept and it works fine. But as you see both the function (f) and its derivative (df) depend on another function g (In this example, it looks trivial and can be written in another way but actual functions are much more complicated).
I was wondering if I can calculate g only once at each iteration and then use that value within the class. Considering that f and df get updated in minimize multiple times so at each step g should be re-evaluated as well.
Thanks!
from scipy.optimize import minimize
class Minimization(object):
'''A class to optimizae a function'''
def __init__(self,x,y):
self.x = x
self.y = y
self.p = np.array([x,y])
def g(self,x,y):
return x-y
def f(self,p):
return (self.g(*p) - 1)**2
def df(self,p):
fprime = 2*(self.g(*p) - 1)
return np.array([fprime,-fprime])
def optimize(self):
P1 = minimize(fun=self.f, x0=self.p, args=(), method='Newton-CG',jac=self.df)
return P1
m = Minimization(2,4)
m.optimize()
#fun: 0.0
# jac: array([ 0., -0.])
#message: 'Optimization terminated successfully.'
# nfev: 3
# nhev: 0
# nit: 2
#njev: 6
#status: 0
#success: True
# x: array([ 3.5, 2.5])
What you want is called "memoizing". When the function g calculates a value it stores the result in a dictionary, indexed by the arguments x, y. Every time g is called it checks the dictionary to see if the value it needs is already stored there. If you need to reset the values, you clear the dictionary. Something like this:
class Minimization(object):
'''A class to optimizae a function'''
def __init__(self,x,y):
self.x = x
self.y = y
self.p = np.array([x,y])
self.cache = {} # previously computed values of g
def g(self,x,y):
cache_index = (x, y)
if cache_index in self.cache: # check cache first
return self.cache[cache_index]
value = x - y
self.cache[cache_index] = value # save for later
return value
def f(self,p):
return (self.g(*p) - 1)**2
def df(self,p):
fprime = 2*(self.g(*p) - 1)
return np.array([fprime,-fprime])
def optimize(self):
self.cache.clear() # Blow the cache
P1 = minimize(fun=self.f, x0=self.p, args=(), method='Newton-CG',jac=self.df)
return P1
To complement Paul's answer, you could define a class aggregating caching-like methods that you will then (re-) use as decorator.
import functools as ft #<------ used to keep meth-related docstring
class Cache(object):
def __init__(self):
self._cache = {}
#classmethod
def _property(cls, meth):
#property
#ft.wraps(meth)
def __property(cls):
meth_name = meth.__name__
if meth_name not in cls._cache:
cls._cache[meth_name] = meth(cls)
return cls._cache[meth_name]
return __property
#classmethod
def _method(cls, meth):
#ft.wraps(meth)
def __method(cls, *args, **kwargs):
meth_key = '{}_{}'.format(meth.__name__, args)# <---- considered as string so as avoid unhashable-type errors
if meth_key not in cls._cache:
cls._cache[meth_key] = meth(cls, *args, **kwargs)
return cls._cache[meth_key]
return __method
And then using the class Cache as ancestor to Minimization, as follows
import numpy as np
from scipy.optimize import minimize
class Minimization(Cache):#<----------Inherits of Cache instead of object
'''A class to optimizae a function'''
def __init__(self,x,y):
super(Minimization,self).__init__()
self.x0 = x # I changed the names because as it stands,
self.y0 = y # these attributes are actually used as first guesses
self.p0 = np.array([x,y]) # for the resolution process
#Cache._method
def g(self, x, y):
return x - y
##Cache._method
def f(self,p):
return (self.g(*p) - 1)**2
##Cache._method
def df(self,p):
fprime = 2*(self.g(*p) - 1)
return np.array([fprime,-fprime])
#Cache._property
def optimized(self):#<----- I changed the name into optimized to make it representative of what it is, a property
return minimize(fun=self.f, x0=self.p0, args=(), method='Newton-CG',jac=self.df)
Use Case (tested under Python 2.7.11 and 3.6.1)
>>> m = Minimization(2,4)
>>> # Take care to clear the cache if optimized is not called for the first time and that you changed one of its "dependencies", doing m._cache.clear().
>>> # something you may want to do is simply removing the #Cache._property decorator
>>> m.optimized
status: 0
success: True
njev: 6
nfev: 3
fun: 0.0
x: array([ 3.5, 2.5])
message: 'Optimization terminated successfully.'
nhev: 0
jac: array([ 0., -0.])
Without having looked too deeply at the code itself, here is a sample class to demonstrate how to calculate a value once and avoid recomputing it on each invocation. You could also make this a property.
class StackOverflow:
def __init__(self, value=None):
self._value = value
def compute_value(self):
if self._value is None:
self._value = 100 # Compute value here
return self._value
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.