Dynamic sizing a 'Matrix' type Object ... is this possible ... ?

boyfarrell

Registered
Hi all,

It would be really nice for me to have an object called 'Slice' that is a matrix of a particular size. It would be really really slick programming :D if I could assign the number of row and columns as I go along. That is to have 'freeze-dyed image' of what a matrix is and then just add the number of rows and columns you need when you start creating instances.

Is this possible?

Have a look at the code below to see what I mean (doesn't compile):
Code:
@interface Slice : NSObject
{
	unsigned int dim1;
	unsigned int dim2;
	double chop[dim1][dim2];
}
-(void) setDim1To: (unsigned int) dimension1;
-(void) setDim2To: (unsigned int) dimension2;
Anybody got any tricks up there sleeves?
 

lurk

Mitä?
IT is possible but not using static sized arrays, which is what you get in almost any case where you use []'s to allocate them. What you need to do is declare chop to be a double ** and then malloc the appropriately sized block of memory at runtime.

Your objects must necessarily be of a fixed size so that the compiler can know how to copy them, stick them in an array, and so on.

-Eric
 

boyfarrell

Registered
Yeah, Thanks.

So what your saying is that it is possible in C but not possible using an object oriented approach? That's a shame if so.

I'll play around with malloc for a bit, cheers!
 

Captain Code

Moderator
Staff member
Mod
You could do it with vectors. Have a vector that stores all the rows(in essence this is the matrix), and have one other vector contained in that first vector that contains the actual cell data.

Then when you want to add a new row to the matrix, you create a vector and append that vector to your matrix vector.
 

boyfarrell

Registered
Is this with the vector class that comes with the C++ library? I know that the C++ vector lib has that useful dynamic size property.
 

Captain Code

Moderator
Staff member
Mod
Yes.
Code:
#include <vector>
It's quite dynamic and handles memory managment by itself. It can hold virtually any type of object.
 

lurk

Mitä?
Both C++ and Objective-C include C as a basis, you were already using C through the [] notation. You really need to lear about the different types of storage allocation used in C. What goes on the stack and what gets allocated in the heap in order to have this stuff make sense.

As for the <vector> that is C++. The Objective-C parallel would be to use NSArray or one of its relatives. Another important thing to keep in mind is that <vector> is not actually an example of object-oriented programming, but rather generic programming. Objective-C is OO but it does not support generic programming.
 

Captain Code

Moderator
Staff member
Mod
If you use the vector class inside your own class then I'd think it's OOP. My suggestion is to incorporate it in your own class but that your class manages appending and creating vectors when it needs to.

You can still mix C++ with Objective-C, although I haven't tried actually using vector in any Objective-C class. It should work though.
 

Viro

Registered
A question about NSArray, does it hold primitives? If it only deals with NSObjects as I'm assuming it does, it would be immensely slow for a Matrix that had to deal with primitive types like double. C++'s vector class will be far more suitable.
 

kainjow

Registered
Using C++ objects in Objective-C isn't as easy as one might think. You first have to rename your .m file to .mm and then any other class that uses this class has to have its .m file renamed to .mm... it's really not a good idea to use C++ unless you absolutely need it. Cocoa provides much better classes then C++, and it's just about as fast too.

I'd suggest using an NSArray that holds other NSArrays, instead of vectors. This way it's 100% Cocoa/Objecive-C and not Objective-C++. Then you can write convenient methods to ease accessing objects from it like valueAtX:Y, instead of using [[array1 objectAtIndex:indexX] objectAtIndex:indexY];

But the only draw back with using NSArrays is you can't use primitives like int or double. You would need to put those inside an NSNumber ([NSNumber numberWithDouble:doubleValue]).

For dealing with relatively small data, you won't notice any speed issues at all. But working with vectors in comparison to NSArrays is a pain.
 

Viro

Registered
kainjow said:
But the only draw back with using NSArrays is you can't use primitives like int or double. You would need to put those inside an NSNumber ([NSNumber numberWithDouble:doubleValue]).

For dealing with relatively small data, you won't notice any speed issues at all. But working with vectors in comparison to NSArrays is a pain.
The data size isn't going to be the determining factor in causing NSArray to be slower than the C++ vector class. It's the frequency of access to the elements of the array. If you are going to access the array many times within loops, as is the case in most scientific simulations, you will notice the performance hit of NSArray regardless of the size of your data set. This is because you need to send a message to the NSArray to retrieve the element you are interested in, then you need to send a message to the NSNumber wrapper to get the value of the primitive you want to access. Objective-C's message passing system works fine for most apps, but if you are dispatching messages hundreds of times in loops, you will notice the difference.

IMHO, this makes Objective-C quite ill suited for scientific coding where performance is paramount. C++'s vectors do not suffer from such a drawback. Primitives can be stored in the vector (removing the need for a wrapper class like NSNumber), and accessor methods to the vector are inlined (removing the overhead of the message dispatch system). This doesn't mean that C++ is perfect, but if you are interested in speed, and you like to write succinct code, perhaps (pure) Objective-C isn't the best choice.
 

kainjow

Registered
Ok so I was curious as to how to properly dynamically allocate memory for multidimensional arrays in C, so I created a sample app, but it seems to crash whenever I try to write to the array "data". Anyone see what's wrong with the code?? :)
Code:
// http://vergil.chemistry.gatech.edu/resources/programming/c-tutorial/dynamic.html

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
	double **data;
	int rows, columns;
} Matrix;

void CreateMatrix(Matrix *m, int rows, int columns)
{
	int i;
	
	m = malloc(sizeof(Matrix));
	m->data = malloc(sizeof(double *) * rows);
	
	for (i=0; i<rows; i++)
		m->data[i] = malloc(sizeof(double) * columns);
	
	m->rows = rows;
	m->columns = columns;
}

void FreeMatrix(Matrix *m)
{
	int i;
	for (i=0; i<m->rows; i++)
		free(m->data[i]);
	free(m->data);
	free(m);
}

int main()
{
	Matrix *m;
	int x, y;
	
	CreateMatrix(m, 10, 5);
	
	// set initial values to 0.0
	for (y=0; y<m->rows; y++)
		for (x=0; x<m->columns; x++)
			m->data[x][y] = 0.0;
	
	// output values
	for (y=0; y<m->rows; y++)
		for (x=0; x<m->columns; x++)
			printf("value at %d,%d: %f", x, y, m->data[x][y]);
			
	FreeMatrix(m);
			
	return 0;
}
 

boyfarrell

Registered
I certainly happier with using 'pure' objective-c than using cocoa because my application links with others that except primitives such as gnuplot. However, I am using the foundation framework for memory management.

Also, when somebody comes along in the future they will be able to understand what I've done because it looks so much like C and C++: they won't have a cocoa learning curve. And as you pointed out speed is certainly an issue. I'm iterating to solve equations, one complete iteration will need about a billion access array element calls. And to get the final answer it will need to do that (iterate) 20 times!

In MATLAB the program spend about 2 seconds per complete iteration. I know it's hard to guess, but what kind of performance increase might I expect from do this in 'pure' objective-c. Because it's C based you might expect if to be about 10 times faster - is somebodys estimate that I know.
 

boyfarrell

Registered
Hi I have just run your code and get:
Code:
DynamicAllocation has exited due to signal 10 (SIGBUS).
Last time I got this message it was when I was calling and external program but my path variable wasn't set. The code compiled but at run time it could find what it need?

Could that be applicable here? Sorry I can't be more help.
 

Viro

Registered
kainjow said:
Ok so I was curious as to how to properly dynamically alloc memory for multidimensional arrays in C, so I created a sample app, but it seems to crash whenever I try to write to the array "data". Anyone see what's wrong with the code?? :)
Code:
// http://vergil.chemistry.gatech.edu/resources/programming/c-tutorial/dynamic.html

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
	double **data;
	int rows, columns;
} Matrix;

void CreateMatrix(Matrix *m, int rows, int columns)
{
	int i;
	
	m = malloc(sizeof(Matrix));
	m->data = malloc(sizeof(double *) * rows);
	
	for (i=0; i<rows; i++)
		m->data[i] = malloc(sizeof(double) * columns);
	
	m->rows = rows;
	m->columns = columns;
}

void FreeMatrix(Matrix *m)
{
	int i;
	for (i=0; i<m->rows; i++)
		free(m->data[i]);
	free(m->data);
	free(m);
}

int main()
{
	Matrix *m;
	int x, y;
	
	CreateMatrix(m, 10, 5);
	
	// set initial values to 0.0
	for (y=0; y<m->rows; y++)
		for (x=0; x<m->columns; x++)
			m->data[x][y] = 0.0;
	
	// output values
	for (y=0; y<m->rows; y++)
		for (x=0; x<m->columns; x++)
			printf("value at %d,%d: %f", x, y, m->data[x][y]);
			
	FreeMatrix(m);
			
	return 0;
}
It's a common problem in C, and it is related to pointers :). A basic rule of the thumb is you need to pass a pointer if you want to modify a variable within a function. Thus, if you want to modify a standard variable, you pass a pointer to that variable to a function(i.e. Matrix *m). If you want to modify a pointer, you need to pass a pointer to a pointer to that variable (i.e. Matrix **m). If you want to modify a pointer to a pointer, you need to pass a pointer to a pointer to a pointer (i.e. Matrix ***m). The process goes on ad infinitum until your compiler crashes, but you see the pattern :).

That is why the CreateMatrix function isn't doing what you think it's doing. The changes made to Matrix *m in the function isn't being kept after the function exits. If you want to make the changes stick, you need to make a pointer to a pointer, i.e. Matrix **m. This will make the code compile, and it will run as expected.

Another reason why I think Java and C# and languages that did away with pointers got it right.
 

Viro

Registered
boyfarrell said:
In MATLAB the program spend about 2 seconds per complete iteration. I know it's hard to guess, but what kind of performance increase might I expect from do this in 'pure' objective-c. Because it's C based you might expect if to be about 10 times faster - is somebodys estimate that I know.
Depends on what you code is doing :). If all your code does is access matrix elements, and _does not_ resize the matrix, the code will run fast and nearly as fast as the equivalent C code since the MATLAB JIT compiler is quite good. Rewriting will not bring you much speed benefit.

However, if your code makes lots of subroutine calls, especially to your own hand crafted .m files, MATLAB starts to slow down. If you call built in MATLAB functions, the MATLAB compiler may be able to optimize the code still, but if it is your own function calls, you are best rewriting it in another language.

A good language to write code in, especially if you want to use all the nice MATLAB plotting tools is Java. Surprised? You get speed that is nearly equal to C, without the horrible contorted interface called MEX which is needed if you want to interface your code with C. You get to run your Java class from within MATLAB, call your class methods within MATLAB, and basically manipulate all your classes fields from directly within MATLAB.
 

kainjow

Registered
Viro said:
It's a common problem in C, and it is related to pointers :). A basic rule of the thumb is you need to pass a pointer if you want to modify a variable within a function. Thus, if you want to modify a standard variable, you pass a pointer to that variable to a function(i.e. Matrix *m). If you want to modify a pointer, you need to pass a pointer to a pointer to that variable (i.e. Matrix **m). If you want to modify a pointer to a pointer, you need to pass a pointer to a pointer to a pointer (i.e. Matrix ***m). The process goes on ad infinitum until your compiler crashes, but you see the pattern :).

That is why the CreateMatrix function isn't doing what you think it's doing. The changes made to Matrix *m in the function isn't being kept after the function exits. If you want to make the changes stick, you need to make a pointer to a pointer, i.e. Matrix **m. This will make the code compile, and it will run as expected.

Another reason why I think Java and C# and languages that did away with pointers got it right.
Ahh, you were right Viro :D thanks :)

Here's my revised (and improved!) code. Note to boyfarrell: you could easily put this into an Objective-C class, and use realloc for increasing the array's size, but you'll still be a little slowed down by the use of Objective-C's messaging system, so if you want ultra speed, use as little as Objective-C as you can, and use straight C structs and such.
Code:
// http://vergil.chemistry.gatech.edu/resources/programming/c-tutorial/dynamic.html

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define TYPE int

typedef struct
{
	TYPE **data;
	int rows, columns;
} Matrix;

void CreateMatrix(Matrix **m, int rows, int columns)
{
	int i;
	
	*m = malloc(sizeof(Matrix));
	(*m)->data = malloc(sizeof(TYPE *) * rows);
	
	for (i=0; i<rows; i++)
		(*m)->data[i] = malloc(sizeof(TYPE) * columns);
	
	(*m)->rows = rows;
	(*m)->columns = columns;
}

void FreeMatrix(Matrix **m)
{
	int i;
	for (i=0; i<(*m)->rows; i++)
		free((*m)->data[i]);
	free((*m)->data);
	free(*m);
}

void FillMatrix(Matrix **m)
{
	// set random value to each item in the matrix
	int x, y;
	for (y=0; y<(*m)->rows; y++)
		for (x=0; x<(*m)->columns; x++)
			(*m)->data[x][y] = (TYPE)(rand()%50);
}

void OutputMatrix(Matrix *m)
{
	int x, y;
	for (y=0; y<m->rows; y++)
	{
		printf("%d:\t", y);
		for (x=0; x<m->columns; x++)
		{
			printf("%d\t", m->data[x][y]);
		}
		printf("\n");
	}
}

int main()
{
	Matrix *m;
	
	srand(time(NULL));
	
	CreateMatrix(&m, 10, 5);
	FillMatrix(&m);
	OutputMatrix(m);
	FreeMatrix(&m);
			
	return 0;
}
 
Top