[Help] Matrix with undetermined dimension

I tried to write a program which can perform matrix multiplication with undetermined dimensional matrix (the dimensional of matrix will be read from input file). But the function to take action with the matrix didnt work. Please give me some help. thanks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>		
#include <fstream>
#include <iomanip>
#include <math.h> 		
#include <stdio.h>
#include <stdlib.h>
using namespace std;


void print_matrix (A[now][ncol])
{
	for(int i=0;i< nrow;i++)
	{
		for(int j=0;j< ncol;j++)
		{
			cout << A[i][j] << "\t" ;
		} cout << "\n";
	}
}

int main()
{
	int nrow, ncol;
	ifstream inpf;
	inpf.open("matrix.txt");	

	inpf >> nrow;	
	inpf >> ncol;
// Size of A	
	double **A;
	A = new double*[nrow];
	for(int i=0;i<nrow;i++)
		A[i]=new double[ncol];
// Declaring member value for A
	for(int i=0;i<nrow;i++)
		for(int j=0;j<ncol;j++)
			inpf >> A[i][j];
// call function
print_matrix(A);
//
return 0;
}
You should declare print_matrix like this:
void print_matrix (double **A , int nrow, int ncol)
and call it like this:
print_matrix(A, nrow, ncol);

Also don't forget to delete your matrix when you are finished with it.
Is this homework or is there another reason not to use a vector<vector<double>> ?
Last edited on
You would be better with either:
(1) a one-d array, mapped to 2-d;
or, if you still want 2-d indexing,
(2) a vector< vector<double> > (as @Thomas1965 suggested).

With a 1-d array:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>             
#include <fstream>
using namespace std;

void print_matrix( double *A, int nrow, int ncol )
{
   for ( int i = 0; i < nrow; i++ )
   {
      for( int j = 0; j < ncol; j++ ) 
      {
         cout << A[ncol*i+j] << '\t'; // Mapping between 1-d and 2-d
      }
      cout << '\n';
   }
}

int main()
{
   int nrow, ncol;
   ifstream inpf( "matrix.txt" );
   inpf >> nrow >> ncol;

   double *A = new double[nrow*ncol];
   for ( int ij = 0; ij < nrow * ncol; ij++ ) inpf >> A[ij];

   print_matrix( A, nrow, ncol );

   delete [] A;         // Tidy up
}


1	2	3	4	
5	6	7	8	
9	10	11	12


With a vector< vector<double> >:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>             
#include <fstream>
#include <vector>
using namespace std;

void print_matrix( const vector< vector<double> > &A )
{
   int nrow = A.size();
   int ncol = A[0].size();

   for ( int i = 0; i < nrow; i++ )
   {
      for( int j = 0; j < ncol; j++ ) 
      {
         cout << A[i][j] << '\t';
      }
      cout << '\n';
   }
}

int main()
{
   int nrow, ncol;
   ifstream inpf( "matrix.txt" );
   inpf >> nrow >> ncol;

   vector< vector<double> > A( nrow, vector<double>( ncol ) );
   for ( int i = 0; i < nrow; i++ )
   {
      for( int j = 0; j < ncol; j++ ) inpf >> A[i][j];
   }

   print_matrix( A );
} 



Because the vector carries all the information about itself, you can also avoid explicitly passing or determining nrow and ncol and make better use of range-based for-loops. e.g.
1
2
3
4
5
6
7
8
void print_matrix( const vector< vector<double> > &A )
{
   for ( auto &row : A )
   {
      for( auto e : row ) cout << e << '\t';
      cout << '\n';
   }
}
Last edited on
You could create a simple class to overload operator[]. Returning a pointer to the beginning of a row allows the language-level operator[] to handle the second dimension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <iomanip>
#include <algorithm>

template<typename T>
class Matrix
{
    size_t mRows, mCols;
    T* mData;

public:
    Matrix(size_t r, size_t c) : mRows(r), mCols(c), mData(new T[r * c]) {
        std::fill(mData, mData + mRows * mCols, 0);
    }

    ~Matrix() { delete [] mData; }

          T* operator[](size_t r)       { return &mData[r * mCols]; }
    const T* operator[](size_t r) const { return &mData[r * mCols]; }

    size_t rows() const { return mRows; }
    size_t cols() const { return mCols; }
};

template<typename T>
std::ostream& operator<<(std::ostream& os, const Matrix<T>& m) {
    auto width = os.width(); // save current width to apply to all elements
    for (size_t r = 0; r < m.rows(); ++r)
    {
        for (size_t c = 0; c < m.cols(); ++c)
            os << std::setw(width) << m[r][c] << ' ';
        os << '\n';
    }
    return os;
}

int main()
{
    Matrix<int> m(5, 10);

    for (auto r = 0u; r < m.rows(); ++r)
        for (auto c = 0u; c < m.cols(); ++c)
            m[r][c] = (c+1) * (r+1);

    std::cout << std::setw(3) << m;
}

Using a matrix flexible class is the preferred solution; that's what object oriented programming is all about.

You can then add operations across matrices.

There are math libraries around that do this sort of thing, unless you need to write your own.
e.g. https://sourceforge.net/projects/arma/
Last edited on
Numerical arrays might be easier in other languages.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
program demo
   implicit none
   real, allocatable :: A(:,:)
   integer i, nrow, ncol
   character (len=20) fmt

   open( 10, file = "matrix.txt" )
   read( 10, * ) nrow, ncol
   allocate( A(ncol,nrow) )  
   read( 10, * ) A
   A = transpose( A )        ! column-major -> row-major

   write( fmt, "( '( ', i0, '( g10.3, 1x ) )' )" ) ncol
   write( *, fmt ) ( A(i,:), i = 1, nrow )

end program demo


gfortran -Wall -pedantic demo.f90 & a.exe

  1.00       2.00       3.00       4.00    
  5.00       6.00       7.00       8.00    
  9.00       10.0       11.0       12.0 
Last edited on
Fortran is actually pretty awesome.
It's outstanding for numerical operations with arrays because of its whole-array operations, array sections, elemental operations and elemental functions, vector subscripts, built-in routines like matmul() and transpose(), masking constructs like where ... elsewhere ... end where, etc. It has brilliant math-function routines built in as standard as well. As of fortran 90 it had modules, and as of fortran 2003 it is object-oriented.

It's lousy for all the clever stuff that C++ can do, with timers, regex, and random numbers etc. Top of my wish-list for fortran would be template functions: you can have "generic" overloaded functions, but it's hard work compared with C++'s abstraction mechanisms.

So you win some, you lose some with each language.
Last edited on
The writes are somewhat obscure. I can't quite figure them out.
tpb wrote:
The writes are somewhat obscure. I can't quite figure them out.


Each write is of the form
write( where_to, what_format ) output_list
where_to can be a file number, character variable, or * (meaning standard out; e.g. console)

The first write
   write( fmt, "( '( ', i0, '( g10.3, 1x ) )' )" ) ncol

is just to create the format for the second. It writes the necessary bits into the character variable fmt - a bit like a stringstream in c++, I guess - and the only edit descriptor is the i0, which will absorb the value of ncol. If ncol is 4 then I'm trying to get "( 4( g10.3, 1x ) )" in fmt, but that 4 depends on the number of items in a row, so I have to create this string on the fly. The edit descriptor i0 means "integer in whatever width is needed"; g10.3 means a generalised floating or fixed point real with width 10 and 3 sig figs; 1x means one space.

The second write
   write( *, fmt ) ( A(i,:), i = 1, nrow )

uses the format inside variable fmt to write out the array A. Then A(i,:) is an "array section", meaning the ith row, or A(i,1),A(i,2) ... A(i,ncol) here. Then there's an outer "implied do loop" over i. (I originally had nested implied do loops, but I edited it to use the shorter form with an array section). If written as a single write statement like this it will use the format repeatedly, with a line feed between each use, until all elements are output. The format was set up in the first write statement to give exactly the right number of elements in a row.


For the record, the input file that I was using, matrix.txt, looked like this:
3
4
1  2  3  4
5  6  7  8
9 10 11 12

It's a list-directed single read statement, so it doesn't matter whether the initial 3 and 4 are on the same line or successive lines.


If you wanted a more general matrix-writing routine, you could do something like the following. Note that the module MyMod could be extended to contain any other fancy array routines. However, fortran has so many built into the standard that there wouldn't be many here.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
module MyMod
   implicit none

contains
   subroutine printMatrix( A, basefmt )
      real, intent( in ) :: A(:,:)
      character (len=*) basefmt
      integer i, nrow, ncol
      character (len=30) fmt

      nrow = ubound( A, 1 )
      ncol = ubound( A, 2 )
      write( fmt, "( '( ', i0, '( ', a, ', 1x ) )' )" ) ncol, basefmt
      write( *, fmt ) ( A(i,:), i = 1, nrow )
   end subroutine printMatrix

end module MyMod


program demo
   use MyMod
   implicit none
   real, allocatable :: A(:,:)
   integer nrow, ncol

   open( 10, file = "matrix.txt" )
   read( 10, * ) nrow, ncol
   allocate( A(ncol,nrow) )  
   read( 10, * ) A
   A = transpose( A )        ! column-major -> row-major

   call printMatrix( A, "g10.3" )

end program demo

Last edited on
Very clean-looking and concise. I can see why people like it.
Topic archived. No new replies allowed.