3

I have to write a function that reads a two-dimensional array of doubles from a binary file (.dat) structured in one single column, whose name is provided by the single input argument of the function. The format of the file is the following: First of all, there are two uint32 numbers which correspond to the number of rows and columns of the array. After that, there is a double number which is the number of non-zero elements on the array. And then each non-zero element of the array is represented by two uint32 scalars and a double scalar in the file in this order: its row index (uint32), its column index (uint32), and its value (double). An example could be:

5
4
2
1
1
8
2
2
9

Which means that the array has 5 rows and 4 columns, a total of 2 non-zero elements. These elements will be found in position (1,1) (with a value of 8) and position (2,2) (with a value of 9). All the other elements are equal to 0. Therefore, the array would be:

8  0  0  0
0  9  0  0
0  0  0  0
0  0  0  0
0  0  0  0

The function must return the two-dimensional array that it reads from the file as an output argument, and if there is a problem opening the file, the function returns an empty array. For the moment I have tried with this code:

function A = sparse_array_in( filename )
fid = fopen( filename,'rt' );
if fid < 0
    A = [];
    return;
end
% Get total number of elements on the file
n = 0;
while (fgets(fid) ~= -1),
  n = n+1;
end
% Close then reopen
fclose(fid);
fid = fopen( filename,'rt' );
% Read size of array and number of non-zero elements
rows = fread( fid,1,'uint32' );
cols = fread( fid,1,'uint32' );
dims = [ rows,cols ];
non_zero = fread( fid,1,'uint32' );
% Create array of zeros
A = zeros( dims );   
% Fill array A with the values from the file
for i = 1:non_zero
    r = fread( fid,1,'uint32' );
    c = fread( fid,1,'uint32' );
    v = fread( fid,1,'double' );
    A(r,c) = v;
end
fclose( fid );
end

But it seems that it is not working. What am I missing?

2
  • I have to write the function and then submit it on a grader that the teacher provided, and this grader tells you whether the function is correct or not, but it does not say what is wrong. I have been trying for hours but it won't work and I hoped somebody could help me figure out what I am missing, because I cannot see any error... Commented Jun 8, 2015 at 19:57
  • You definitely need to create your own test file since you don't have access to the "grader" files. Start with a very simple one, then add a few extra ones with obvious errors and see if your code can handle them. Commented Jun 8, 2015 at 20:06

1 Answer 1

3

There are a few of problems with your code:

  1. If the file ID is negative, you should not only return the empty array (as you're doing), but also make sure the code doesn't proceed from that point. I would stick a return statement right after the assignment to A:

    if fid < 0
        A = [];
        return;
    end
    
  2. Next when you're determining the number of lines in your text file, be advised that you're advancing the file pointer each time you call fgets and so when you finally finish reading all of the lines, the file pointer points at the end of the text file. Any further calls to fread, fgets, or any of the f* family that reads things from files will not give you anything because you're at the end of the file. What you need to do is close the file and open it again so that you can start reading from the file again. Therefore, close the file when you read the number of lines, then open it up again:

    % Get total number of elements on the file
    n = 0;
    while (fgets(fid) ~= -1),
      n = n+1;
    end 
    %// Close then reopen
    fclose(fid);
    fid = fopen( filename,'rt');
    
  3. You're not using fread right. The second parameter tells you how many numbers of a particular type you want to read in. You are using 1, 2 or 3 which means that you're reading 1, 2 or 3 numbers of a particular type. Because you're using fread to read in individual numbers per call, they should all be 1. Also, determining the total number of lines seems rather superfluous to me. If you are given the total number of non-zero elements, why bother figuring out how many lines there are? You already know how many non-zero elements there are, so just iterate from 1 up to as many non-zero numbers. Therefore, try this:

    % Read size of array and number of non-zero elements
    rows = double(fread( fid,1,'uint32' )); %// Change
    cols = double(fread( fid,1,'uint32' )); %// Change
    dims = [ rows,cols ];
    non_zero = fread( fid,1,'uint32' ); %// Change
    % Create array of zeros
    A = zeros( dims );   
    % Fill array A with the values from the file
    for i = 1 : non_zero %// Change
        r = fread( fid,1,'uint32' ); %// Change
        c = fread( fid,1,'uint32' ); %// Change
        v = fread( fid,1,'double' ); %// Change
        A(r,c) = v;
    end
    %A = reshape( A,dims' ); %// Why are you reshaping?
    fclose( fid );
    

Minor comment: Why are you reshaping the matrix? If you already know the row and column locations of your matrix and are putting them exactly where they're supposed to go, why bother transposing?


Therefore, with the above comments, your code would look like this:

function A = sparse_array_in( filename )
fid = fopen( filename,'rt' );
if fid < 0
    A = [];
    return; %// Change
end

% Read size of array and number of non-zero elements
rows = fread( fid,1,'uint32'); %// Change
cols = fread( fid,1,'uint32'); %// Change
dims = [ rows,cols ];
non_zero = fread( fid,1,'uint32' ); %// Change
% Create array of zeros
A = zeros( dims );   
% Fill array A with the values from the file
for i = 1:non_zero
    r = fread( fid,1,'uint32' ); %// Change
    c = fread( fid,1,'uint32' ); %// Change
    v = fread( fid,1,'double' ); %// Change
    A(r,c) = v;
end
%// Change - remove reshape
fclose( fid );
end

Here's an example that shows that it works for a binary file. I've created the following scenario:

5
7
4
1
1
1
2
2
2
3
3
3
4
4
4

This is a 5 x 7 matrix where (1,1) = 1, (2,2) = 2, (3,3) = 3, (4,4) = 4 with 4 non-zero values. I create a binary file, then use the function I fixed above to get the results:

fid = fopen('sparse_binary.dat', 'w');
fwrite(fid, 5, 'uint32');
fwrite(fid, 7, 'uint32');
fwrite(fid, 4, 'uint32');
fwrite(fid, 1, 'uint32');
fwrite(fid, 1, 'uint32');
fwrite(fid, 1, 'double');
fwrite(fid, 2, 'uint32');
fwrite(fid, 2, 'uint32');
fwrite(fid, 2, 'double');
fwrite(fid, 3, 'uint32');
fwrite(fid, 3, 'uint32');
fwrite(fid, 3, 'double');
fwrite(fid, 4, 'uint32');
fwrite(fid, 4, 'uint32');
fwrite(fid, 4, 'double');
fclose(fid);
A = sparse_array_in('sparse_binary.dat');

I get for A:

A =

     1     0     0     0     0     0     0
     0     2     0     0     0     0     0
     0     0     3     0     0     0     0
     0     0     0     4     0     0     0
     0     0     0     0     0     0     0

... which is what we expect.

Sign up to request clarification or add additional context in comments.

14 Comments

I understand what you did, but the grader says it is still not correct. I believe that one problem could be that the grader passes the file such as: 5 7 4 1 1 1 2 2 2 3 3 3 4 4 4, or maybe even on a column vector. Could this be what causes the error in your solution?
@Hec46 - I need to know the exact way the grader is passing the data or else I will never get it correct. I assumed that the text file was space delimited and carriage return separated.
@Hec46 - The way the data is formatted was also not made clear in your post. Please update it so that we know exactly how the file is structured.
Sorry, let's see if I can explain it better. On the first task, I was asked to write a function that given an array and a filename, writes this array on a binary file with the structure I explained on the post. After testing it, I see that it does it on a column vector. Then, this .dat file can be passed to the second function, and it should return the same exact array I passed to the first function. The teacher just told me that, in order to compare the results, I need to use isequal() and obtain a 1 as a result. I hope this clarifies it a little bit, I will edit the post now. Thank you!
@Hec46 - Ah so if it's binary, then your use of fread is justified. Still I will wait until you update your post.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.