Updating attributes within a class

  • Python
  • Thread starter schniefen
  • Start date
  • Tags
    Class
In summary: You could add a method to your class that does the change for you, like this:def _matrix_change(self,old_matrix,new_matrix): self._matrix=new_matrix #setting up an internal representation of CSR, A and JA self._A=self._matrix[self._matrix!=0] self._JA=np.nonzero(self._matrix)[1] #IA
  • #1
schniefen
178
4
TL;DR Summary
I'm creating a sparse matrix class and am stuck on how to update the attributes within the class.
I'm working on a sparse matrix class, where I'm creating an internal representation of a random matrix a la CSR (Sparse Matrix). 'A' signifies the non-zero elements in the matrix, 'IA' are the rowpointers and 'JA' the column indices of the non-zero elements.
Python:
import numpy as np
class SparseMatrix:
    def __init__(self,Matrix):
        if not isinstance(Matrix,np.ndarray):
            raise TypeError('Matrix should be of type np.ndarray')
        self._matrix=Matrix
        #setting up an internal representation of CSR, A and JA
        self._A=self._matrix[self._matrix!=0]
        self._JA=np.nonzero(self._matrix)[1]
        #IA
        rowpointer=[0]
        for i in range(self._matrix.shape[0]):
            indices=len(np.nonzero(self._matrix[i])[0])
            rowpointer.append(indices+rowpointer[i])
        self._IA=np.asarray(rowpointer)
        # more attributes
        self._number_of_nonzero=len(np.nonzero(self._matrix)[0])
        self.intern_represent='CSR'
    def __repr__(self):
        return 'A={}\nIA={}\nJA={}'.format(self._A,self._IA,self._JA)
When I change a value in the input matrix, this is registered and updated in the attribute self._matrix. But neither A, IA, or JA are.
Python:
d=np.array([[0,0,0,0],
            [5,8,0,0],
            [0,0,3,0],
            [0,6,0,0]])
f=SparseMatrix(d)
f._matrix[0,0]=9 #change first element of matrix to 9
print(f._matrix)
print(f)
Code:
array([[9,0,0,0],
       [5,8,0,0],
       [0,0,3,0],
       [0,6,0,0]])
A=[5 8 3 6]
IA=[0 0 2 3 4]
JA=[0 1 2 1]
4
A should be equal to [9 5 8 3 6] and _number_of_nonzero should be equal to 5. IA and JA should then also change. How can I update self._A, self._IA and self._JA? I've been experimenting with setter and getter methods, but without success. Furthermore, I'm confused why self._matrix updates automatically.
 
Technology news on Phys.org
  • #2
schniefen said:
How can I update self._A, self._IA and self._JA?

You would have to recalculate them every time the matrix changes. But you don't have any way of automatically catching when the matrix changes. See below.

schniefen said:
I'm confused why self._matrix updates automatically.

It doesn't "update"; the variable self._matrix refers to the same object as the Matrix that you pass to the class constructor. Since it's a reference to the same object, looking at its attributes will show you the same attributes, including any attributes that get updated. But references to objects don't get notified when the objects change, unless you explicitly set up some way for that to happen, so your sparse matrix class won't know when to look for updated attributes to use in recalculating self._A, self._IA, and self._JA.

If the only times that the matrix ever changes is when you change it in your own code, then you could just add methods to your sparse matrix class that do the changes to everything: in other words, instead of changing Matrix directly, you would call a method on your sparse matrix class instance that updates self._matrix (which will change the matrix that you passed to the class constructor) and then updates self._A, self._IA, and self._JA.

If there is other code you don't control that can update the matrix, then you won't have any way of knowing when the matrix gets updated. The only way I could see to solve your problem in that case would be to subclass the matrix class and override the update methods; but then you would have to have a way of telling the other code that you don't control to use your subclass instead of the usual matrix class.
 
  • Like
Likes schniefen
  • #3
PeterDonis said:
If the only times that the matrix ever changes is when you change it in your own code, then you could just add methods to your sparse matrix class that do the changes to everything: in other words, instead of changing Matrix directly, you would call a method on your sparse matrix class instance that updates self._matrix (which will change the matrix that you passed to the class constructor) and then updates self._A, self._IA, and self._JA.
Thanks for a clarifying answer. How would I go about implementing this? I suspect this is what I was after in the first place, i.e. call on a method in the class that changes the value in the matrix for me.
Python:
f._matrix[0,0]=9 # instead of this
f._matrix_change([0,0],9) #maybe something like this?
 
  • #4
schniefen said:
I suspect this is what I was after in the first place, i.e. call on a method in the class that changes the value in the matrix for me.

Yes, that's the sort of thing you need to do; the code in the method _matrix_change would update the matrix and also recalculate the other attributes.
 
  • Like
Likes schniefen
  • #5
Is there any clever way of shortening the recalculations of self._A, self._IA and self._JA when changing the value of the matrix? I've defined my method 'change', but I currently need to repeat the calculations from the __init__ method.

Python:
import numpy as np
class SparseMatrix:
    def __init__(self,A):
        if not isinstance(A,np.ndarray):
            raise TypeError('Matrix should be of type np.ndarray')
        self._matrix=A
        self._A=self._matrix[self._matrix!=0]
        self._JA=np.nonzero(self._matrix)[1]
        rp=[0]
        for i in range(self._matrix.shape[0]):
            indices=len(np.nonzero(self._matrix[i])[0])
            rp.append(indices+rp[i])
        self._IA=np.asarray(rp)
        self.intern_represent='CSR'
        self.number_of_nonzero=len(np.nonzero(self._matrix)[0])
    def change(self,i,j,val):
        self._matrix[i,j]=val
        self._A=self._matrix[self._matrix!=0] # this feels redundant, but probably necessary
        self._JA=np.nonzero(self._matrix)[1]
        rp=[0]
        for i in range(self._matrix.shape[0]):
            indices=len(np.nonzero(self._matrix[i])[0])
            rp.append(indices+rp[i])
        self._IA=np.asarray(rp)
        self.number_of_nonzero=len(np.nonzero(self._matrix)[0])
    def __repr__(self):
        return 'A={}\nIA={}\nJA={}'.format(self._A,self._IA,self._JA)

I'd also like to add a method toCSC where I want to convert my matrix to CSC format. Mathematically this is only CSR of the transpose of the input matrix. However, I'm facing a bit of an odd problem with the intern_represent attribute, which I'd like to change when this method is activated.

Python:
class SparseMatrix:
    ...

    ...
    def toCSC(self):
        m=np.transpose(self._matrix)
        self._matrix=m
        self._A=self._matrix[self._matrix!=0]
        self._JA=np.nonzero(self._matrix)[1]
        rp=[0]
        for i in range(self._matrix.shape[0]):
            indices=len(np.nonzero(self._matrix[i])[0])
            rp.append(indices+rp[i])
        self._IA=np.asarray(rp)
        self.intern_represent='CSC'
        self.number_of_nonzero=len(np.nonzero(self._matrix)[0])
        return self
    def __repr__(self):
        return 'A={}\nIA={}\nJA={}'.format(self._A,self._IA,self._JA)
r=SparseMatrix(d) #d is some matrix
s=r.toCSC()
print(r.intern_represent)
print(s.intern_represent)
Code:
CSC
CSC
Whereas...
Python:
r=SparseMatrix(d) 
print(r.intern_represent)
s=r.toCSC()
print(s.intern_represent)
Code:
CSR
CSC
It seems like I'm changing the instance r as I'm creating s. Can this be avoided?
 
  • #6
schniefen said:
I've defined my method 'change', but I currently need to repeat the calculations from the __init__ method.

Those calculations are already pretty short, so I don't see any urgent need to make them shorter. Also, doing them the same way every time makes the code easier to understand.

schniefen said:
It seems like I'm changing the instance r as I'm creating s.

No, you're returning the same instance r as instance s. Your toCSC method returns self; that means it returns the same instance you called it on.

If you want to avoid that, you need to construct a new SparseMatrix instance in the toCSC method and return it.
 
  • Like
Likes schniefen
  • #7
I'm facing another issue when writing the __mul__ method, where I aim to define multiplication with a vector.

Python:
class SparseMatrix(SparseMatrix):
 
    def __mul__(self,other):
        if isinstance(other,np.ndarray):
            x=SparseMatrix(np.dot(self._matrix,other))
            return x
    def __rmul__(self,other):
        if isinstance(other,np.ndarray):
            x=SparseMatrix(np.dot(other,self._matrix))
            return x
matrix=np.array([[0,0,0,0],
                 [5,8,0,0],
                 [0,0,3,0],
                 [0,6,0,0]])
vector=np.array([2,2,2,2])
print(SparseMatrix(matrix)*vector)
print(vector*SparseMatrix(matrix))
And I'm getting a wrong output for the last print statement. It seems something is not working with __rmul__ method.
Code:
A=[26  6 12]
IA=[0 0 1 2 3]
JA=[0 0 0]
[None None None None]
 
  • #8
Obviously matrix multiplication isn't possible as indicated in the second print statement, and that's probably the cause of the wrong output. But why doesn't np.dot catch this?
 
  • #9
I'm not sure your __rmul__ method is even being called in the second print statement. The numpy array object already has a __mul__ method itself, so I think that's what will be called there. I think __rmul__ only gets called on the right object of a multiplication if the left object doesn't have a __mul__ method.
 

What is "updating attributes within a class"?

"Updating attributes within a class" refers to the process of changing the values of attributes or properties of an object belonging to a specific class in a programming language.

Why is it important to update attributes within a class?

Updating attributes within a class is important because it allows for the dynamic modification of an object's state. This means that the values of the object's attributes can be changed during runtime, allowing for more flexibility and functionality in a program.

How can attributes be updated within a class?

Attributes within a class can be updated using methods or functions that are specifically designed to modify the values of those attributes. These methods or functions can be called from within the class or from outside of the class, depending on the access modifiers set for the attributes.

Can attributes within a class be updated multiple times?

Yes, attributes within a class can be updated multiple times. This is one of the main benefits of updating attributes within a class - it allows for the object's state to be changed as needed, depending on the requirements of the program.

What are some common errors that can occur when updating attributes within a class?

Some common errors that can occur when updating attributes within a class include accessing private attributes from outside of the class, accidentally overwriting existing attribute values, and attempting to update attributes that do not exist within the class.

Similar threads

  • Programming and Computer Science
Replies
1
Views
2K
  • Beyond the Standard Models
Replies
2
Views
2K
  • General Math
Replies
2
Views
4K
Back
Top