Matrix element access

Hello everyone

Lately I've developing a MATRIX class. It went fine (mostly), but now I'm working on a SPARSE MATRIX. (Those unfamiliar with sparse matrix, check the end for a quick explanation). My problem is the following:
When accessing element i,j of the matrix, the user should call something like A(i,j), i.e.

Code:

cout << A(i,j);

Also, the user could like to change the value of the element i,j, so he would call

Code:

A(i,j) = 2;

The point is, in the first use, I can return the element itself and in the second I would have to return the reference to the element, so the user could change it.
So I wrote the code:

I found out only now that the second function was never called. But in the case of the MATRIX, it meant nothing, for everything worked fine.
But in the case of the SPARSE matrix, my functions had to change a little. It became something like

Details have been hid to help visualization. As you can see, I must create a zero element and pass reference to it so the user can change (and I hope the user don't pass another 0.0). The mess here is that anytime it access an element to read, it creates a zero valued element in the matrix and stores it, and that what's wrong.

If anyone can give me a tip on how to use the same function operator() to both tasks, I would be very happy. And if it's not possible, I would be happy to know that as well, thank you very much.

Nepper271.

SPARSE MATRIX

A matrix is said to be sparse if there are many zero elements in it, in fact, many more zeros than non-zeros. As this kind of matrix appears widely on various applications, it's fundamental to research better ways to deal with it. The first thing to consider is that storing all the elements of the matrix is not useful. You store only the non-zero elementos of the matrix and the position they are held. For instance, the matrix

The overloaded const version will only be called if the object itself is const (or used in a context where it is immutable).

The mess here is that anytime it access an element to read, it creates a zero valued element in the matrix and stores it, and that what's wrong.

Basically, you have to fix it such that the matrix does not store elements unless they are supposed to be stored.

Originally Posted by Bjarne Stroustrup (2000-10-14)

I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.

Basically, you have to fix it such that the matrix does not store elements unless they are supposed to be stored.

I must create a space in the vector that stores the elements of the matrix to pass it to the user, so I create one that will simply waste space if the user do something funny like setting it to zero. The elements must be ordered following the matrix rows, so I can't simply push_back it either.

Originally Posted by matsp

Perhaps returning a reference to a proxy object is the right thing here, where the proxy object contains some information to indicate where it belongs?

I'm sorry, I didn't understand what you meant. What is a proxy object?

A proxy object is an object that "takes the place of the real object", such that you could return a reference to the object and when it's being written, it updates the actual cell location. I'm not sure exactly how you would use that here.

The other option is to simply scan [when you do math on the array perhaps] for zero's and remove them...

--
Mats

Compilers can produce warnings - make the compiler programmers happy: Use them!
Please don't PM me for help - and no, I don't do help over instant messengers.

I can't think of a way to force the compiler use a different overload based on on which side of assignment the function is called. What you are attempting is overloading only based on return type (the const-ness of the second version doesn't help you, since you are calling the method on a non-const object) and there is no such thing.

May-be you could use a different function for read-only access that doesn't add elements to the array?

Returning 0 might not be good for a general-purpose container, because someone might want to store 0-s in it. If it is a precondition of the read-only function that the index is valid, perhaps use assert.

I might be wrong.

Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.

The other option is to simply scan [when you do math on the array perhaps] for zero's and remove them...

That was though about it at first, but it would slow things down a bit (every operation would need an additional comparison). My other option, which is what I'm doing now, and will keep if have no other choice, is use A.get(...) and A.set() instead. This way I can check whether the number is zero or not.

I must create a space in the vector that stores the elements of the matrix to pass it to the user, so I create one that will simply waste space if the user do something funny like setting it to zero. The elements must be ordered following the matrix rows, so I can't simply push_back it either.

I think it is pretty simple: if the element at (x, y) exists, return it. Else, throw a std::out_of_range exception. To add an element, the caller should use another member function, e.g., insert().

Originally Posted by Bjarne Stroustrup (2000-10-14)

I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.

But what if the user sets the element to 0?
He needs a "set to 0" detector.
A separate set method may be best.

Yes, I forgot about that.

Originally Posted by Bjarne Stroustrup (2000-10-14)

I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.

Yes, considering I must check if the element exists and must erase it if the user set it to zero, I will use a set function separate from the get function.

My function will be

Code:

A.set (int i, int j, double a)

It will find the element (i, j), if he can't find it, it will create a new element with value a, if a is not zero. If he finds it, it will check whether a is zero. If a is zero, it will erase element (i,j), otherwise it will simply change (i,j) element's value to a.

It will find the element (i, j), if he can't find it, it will create a new element with value a, if a is not zero. If he finds it, it will check whether a is zero. If a is zero, it will erase element (i,j), otherwise it will simply change (i,j) element's value to a.

That sounds correct to me.

By the way, are you really naming your sparse matrix class SPARSE? Note that such all uppercase identifiers are typically reserved by convention for macro names and names of special constants. More typical conventions for class names include capitalising each word in the name (e.g., Sparse or SparseMatrix), adding a C prefix (e.g., CSparse, CSparseMatrix), or simply leaving it all in lowercase with underscore separators.

Originally Posted by Bjarne Stroustrup (2000-10-14)

I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.