I tried to multiply a vector by a matrix but I can't get it to work because the loop always stops at one line. But with no error code, I've tried different ways to write the code into the resulting vector but it doesn't work. The outputs are to control where the loop stops, it stops after res[i] += (A[i][k] * B[k]);.
This is the specific function to perform the vector & matrix multiplication, if you need all the code let me know.
void vector_matrix_multiplication(vector<vector<int>> A,vector<int> B, int col1, int row1, int row2, vector<int>& res) {
int row = row1;
if(row1 < row2)
row = row2;
for(int i = 0; i < row; i++) {
cout << "Loop 1 ";
cout << i << endl;
for (int k = 0; k < col1; k++) {
cout << "Loop 2 " << i << " " << k << endl;
res[i] += (A[i][k] * B[k]);
cout << "Loop 2?" << endl;
}
}
The output of the function (with input A = {{2,3},{4,5}} & B = {1,2} is:
Loop 1 0
Loop 2 0 0
#include <iostream>
#include <vector>
using namespace std;
void vectorinput(vector<int>& a, int col){
cout << "Vector: " << endl;
for(int i = 0; i < col; i++) {
int x;
cin >> x;
a.push_back(x);
}
}
void matrixinput(vector<vector<int>>& a, int row, int col){
cout << "Matrix: " << endl;
for(int i = 0; i < row; i++) {
vector<int> vector;
for(int j = 0; j < col; j++) {
int x;
cin >> x;
vector.push_back(x);
}
a.push_back(vector);
}
}
int main(){
vector<int> vector;
vector<vector<int>> matrix; //Matrix is read in separate function
int row1 = 0; //Number of rows of first matrix
int col1 = 0; //Number of columns of first matrix
int row2 = 0; //Number of rows second matrix (redundant in this case)
int col2 = 0; //Number of columns second matrix
matrixinput(matrix1, row1, col1);
vectorinput(vector2, col2);
int row = row1; //Matrix with number of columns "col1", rows "row" - in this case both are 2
if(row2 > row1)
row = row2; //Vector with number of rows "row2" - in this case 2
vector<int> resvector(row, col1);
vector_matrix_multiplication(matrix2, vector1, col2, row, col1, resvector);
for(int i = 0; i < row; i++) {
cout << resvector[i] << endl;
}
return 0;
}
I hope this clarifies the purpose of the program and the function. I tried to cut it down a little because I have a lot of useless code in it. (Plus I struggled to input the code at first, was not quite sure how the code block works - sorry ^^)
There are following three bugs in your code:
Since you use the following ctor of std::vector
explicit vector(size_type count,
const T& value = T(),
const Allocator& alloc = Allocator());
, the second argument of resvector must be zero.
row1, row2, col1 and col2 are all zero through the main function and thus the loop in vector_matrix_multiplication does not work.
We can also reduce these variables to row and col of the matrix as #n.m. suggests in the comments.
matrix1, matrix2, vector1 and vector2 are not defined.
In summary, the following minimally fixed version will work fine for you:
int main()
{
std::vector<int> vec;
std::vector<std::vector<int>> mat;
int row = 2; //Number of rows of matrix
int col = 2; //Number of columns of matrix
matrixinput(mat, row, col);
vectorinput(vec, col);
std::vector<int> resvector(row, 0);
// 5th argument is redundant as #n.m. suggested
vector_matrix_multiplication(mat, vec, col, row, col, resvector);
for(int i = 0; i < row; i++) {
std::cout << resvector[i] << std::endl;
}
return 0;
}
and welcome to StackOverflow! I suggest you using mathematical libraries for this kind of stuff. The reason is:
they are already tested by someone else
they are efficient and optimized to use advanced CPU features
they are easier to use
I've used two different libraries: glm and Eigen
If you want to build your own library for learning purpose I suggest you looking how these libraries are written (they're open source)
Related
For the past few hours I have been trying to build a C++ module that, upon requesting the input of the user on the size and contents of 2 matrices (restricted to ones that can be multiplied together), then proceeds to multiply them together and return the values of a third answer matrix. While the matrix input commands seem to work based on thorough testing, I can't seem to get a correct answer from my multiplication command, despite going through each step of the algorithm and how it corresponds to actual matrix multiplication. The first value of the answer matrix is correct, and then all succeeding values are incorrect by some factor. Does anyone have any insight as to what could be going wrong?
#include <iostream>
#include <cmath>
using namespace std;
int r, c, a1, a2, b1, b2; //defines row and column indices
double m[1][1], m2[1][1], a[1][1]; //initializes matrices
double b;
int inflag = true;
int repflag = false;
void defmatrix() { //Defines the matrix size of the first inputted matrix
cout << "Matrix Rows: ";
cin >> r;
cout << "Matrix Columns: ";
cin >> c;
}
void fillmatrix() { //Fills the matrix with automatic or user-inputted values
if (inflag == true) {
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
cout << "Number in row " << i + 1 << " and column " << j + 1 << ": ";
cin >> b;
m[i][j] = b;
}
}
} else {
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
m[i][j] = 1;
}
}
}
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
cout << m[i][j] << " ";
}
}
}
void matrixmult() { //Multiplication function for matrix math
if (repflag == false) {
cout << "\n" << "Your second matrix will have " << c << " rows" << "\n";
b1 = c;
a1 = r;
r = c;
cout << "Second matrix columns: ";
cin >> c;
a2 = c;
double m2[r][c] = {};
if (inflag == true) {
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
cout << "Number in row " << i + 1 << " and column " << j + 1 << ": ";
cin >> b;
m2[i][j] = b;
}
}
} else {
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
m2[i][j] = 1;
}
}
}
a[a1][a2];
for (int i = 0; i < a1; i++) {
for (int j = 0; j < a2; j++) {
b = 0;
for (int d = 0; d < b1; d++) {
b = b + (m[i][d] * m2[d][j]);
}
a[i][j] = b;
}
}
for (int i = 0; i < a1; i++) {
for (int j = 0; j < a2; j++) {
cout << a[i][j] << " ";
}
}
}
}
int main() { //main file
defmatrix();
double m[r][c] = {};
fillmatrix();
matrixmult();
}
Thanks in advance!
There is a problem in almost every line. It is easier to point out the good parts. The central for loop that calculates the matrix product seems OK. Most everything else needs to be thrown out and rewritten. This includes all declarations and all function interfaces.
Here's how I would start writing the program.
int main()
{
int rows;
int cols;
int common_size; // columns in the matrix A and rows in the matrix B
std::cout << "Enter number of rows in the result : ";
std::cin >> rows;
std::cout << "Enter number of columns in the result : ";
std::cin >> cols;
std::cout << "Enter the common size : ";
std::cin >> common_size;
Now we need to declare the matrices, but here comes a problem. One would naïvely want to write something like
int a[rows][common_size], b[common_size][cols], c[rows][cols];
but alas, this is not legal C++. This declaration may work with your compiler, or it may not. There are several ways to declare the matrices correctly. The simplest one is to reserve a fixed amount of memory for each one, and just use a portion:
int a[10][10], b[10][10], c[10][10];
Naturally you need to check that the sizes provided by the user do not exceed 10.
Another method is to use the C++ version of variable length array, called [vector]. The declaration of a will look something like this:
std::vector<std::vector<int>> a(rows, std::vector<int>(common_size));
With the second method, there is no real limitation on the matrix sizes.
Neither method is adequate for any real software, but they are enough to complete your C++ exercise. Real software uses more advanced C++ concepts like classes to define matrices. Just something to be aware of.
I will not continue writing it at the same level of detail. This is your task. I will just show what the rest of main could look like.
input_matrix(a, rows, common_size);
input_matrix(b, common_size, cols);
multiply_matrices(a, b, c, rows, common_size, cols);
print_matrix(c, rows, cols);
Note function calls using arguments. Implement these functions, and you are good to go. Note, if you choose vectors, you will need to pass some arguments by reference. In this case you could also write the functions this way:
input_matrix(a);
input_matrix(b);
c = multiply_matrices(a, b);
print_matrix(c);
but this is a talk for another day.
Although you're asking to find mistakes in your code, as your task is interesting I decided to implement my own solution from scratch for you. Even if it is unacceptable answer, still it might be useful for educational purpose.
I made code in a form of class Matrix that supports multiplication operation between two matching matrices like A *= B;. As you did, I also implemented two methods .Input() and .Output() that correspondingly read matrix from std::cin and output to std::cout.
As a bonus there is also a method .At(i, j) that returns reference to element of a matrix with bounds checking, similar to std::vector.
Sure class can be extended to many other matrices operations (like addition A += B; or subtraction A -= B;), but I limited my class to only those things that you used in your original code.
To do what you wanted using my class is simple as few lines of code (that are located further in main() function of following code snippet):
Matrix A, B;
A.Input(); B.Input();
A *= B;
A.Output();
Full code:
Try it online!
#include <stdexcept>
#include <vector>
#include <sstream>
#include <iomanip>
#include <iostream>
#define ASSERT_MSG(cond, msg) { if (!(cond)) throw std::runtime_error("Assertion (" #cond ") failed at line " + std::to_string(__LINE__) + "! Msg: '" + std::string(msg) + "'."); }
#define ASSERT(cond) ASSERT_MSG(cond, "")
class Matrix {
public:
using FloatT = double;
Matrix(size_t rows = 0, size_t cols = 0)
: rows_(rows), cols_(cols) {
Clear();
}
Matrix & Clear() {
m_.clear();
m_.resize(rows_ * cols_);
return *this;
}
size_t Rows() const { return rows_; }
size_t Cols() const { return cols_; }
Matrix & operator = (Matrix && other) {
rows_ = other.rows_;
cols_ = other.cols_;
m_ = std::move(other.m_);
other.rows_ = 0;
other.cols_ = 0;
return *this;
}
FloatT & operator() (size_t i, size_t j) {
return m_[i * cols_ + j];
}
FloatT const & operator() (size_t i, size_t j) const {
return const_cast<Matrix &>(*this)(i, j);
}
FloatT & At(size_t i, size_t j) {
ASSERT_MSG(i < rows_ && j < cols_,
"Matrix index (" + std::to_string(i) + ", " + std::to_string(j) +
") out of bounds (" + std::to_string(rows_) + ", " + std::to_string(cols_) + ")!");
return (*this)(i, j);
}
FloatT const & At(size_t i, size_t j) const {
return const_cast<Matrix &>(*this).At(i, j);
}
Matrix & operator *= (Matrix const & B) {
Matrix const & A = *this;
ASSERT_MSG(A.Cols() == B.Rows(),
"Number of A.Cols " + std::to_string(A.Cols()) +
" and B.Rows " + std::to_string(B.Rows()) + " don't match!");
Matrix C(A.Rows(), B.Cols());
for (size_t i = 0; i < A.Rows(); ++i)
for (size_t j = 0; j < B.Cols(); ++j) {
FloatT sum = 0;
for (size_t k = 0; k < A.Cols(); ++k)
sum += A(i, k) * B(k, j);
C(i, j) = sum;
}
*this = std::move(C);
return *this;
}
Matrix & Input() {
std::cout << "Enter number of rows and columns: ";
std::cin >> rows_ >> cols_;
Clear();
std::cout << "Enter all matrix elements:" << std::endl;
for (size_t i = 0; i < rows_; ++i)
for (size_t j = 0; j < cols_; ++j)
std::cin >> (*this)(i, j);
return *this;
}
Matrix const & Output(size_t precision = 6) const {
std::vector<std::vector<std::string>> cells(Rows(),
std::vector<std::string>(Cols()));
std::ostringstream ss;
size_t max_len = 0;
for (size_t i = 0; i < Rows(); ++i)
for (size_t j = 0; j < Cols(); ++j) {
ss.str("");
ss << std::fixed << std::setprecision(precision)
<< (*this)(i, j);
cells[i][j] = ss.str();
max_len = std::max(max_len, cells[i][j].size());
}
for (auto const & row: cells) {
for (auto const & cell: row)
std::cout << std::string(max_len - cell.size() + 1, ' ')
<< cell;
std::cout << std::endl;
}
return *this;
}
private:
size_t rows_ = 0, cols_ = 0;
std::vector<FloatT> m_;
};
int main() {
try {
Matrix A, B;
A.Input();
B.Input();
A *= B;
A.Output();
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
Input:
Enter number of rows and columns: 3 2
Enter all matrix elements:
1.01 2.02
3.03 4.04
5.05 6.06
Enter number of rows and columns: 2 4
Enter all matrix elements:
7.07 8.08 9.09 10.10
11.11 12.12 13.13 14.14
Output:
29.582900 32.643200 35.703500 38.763800
66.306500 73.447200 80.587900 87.728600
103.030100 114.251200 125.472300 136.693400
I'm using C++ to read from two .txt files. The first number in the .txt file represents the rows. The second number represents the columns. Then the remaining numbers is for the matrix. I'm getting an error while trying to scan the dimensions. I tried declaring two ints. I also tried using constants and I still get errors.
This is the requirements to help understand what I'm trying to do.
[Matrix Addition1
Here is my code.
#include <iostream>
#include <fstream>
#include<iomanip>
#include<string>
using namespace std;
int main() {
/**
* Integer n and m are declared to store the row and column
* respectively
*/
const int n = 8;
const int m = 8;
int arr[n][m];
//int n, m;
/**
* below we create object of file named myFile for file matrix.txt
*/
string filename;
cout << "Enter file name: ";
getline(cin, filename);
ifstream myfile;
myfile.open(filename.c_str());
/**
* scanning dimensions of first matrix
*/
myfile >> n >> m;
/**
* Creating double type 2d array named matrix1
*/
double matrix1[n][m];
/**
* In following nested for loop we scan data into the array matrix1
*/
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
myfile >> matrix1[i][j];
}
}
cout << "MATRIX 1" << endl;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cout << right << setw(5) << matrix1[i][j];
}
cout << endl;
}
cout << endl;
/***
* Data scanning for matrix 2
*/
/**
* Integer p and q are declared to store the row and column
* respectively of matrix2
*/
const int p = 8;
const int q = 8;
int arr2 [p][q];
//int p, q;
/**
* scanning dimensions of first matrix
*/
myfile >> p >> q;
/**
* Creating double type 2d array named matrix2
*/
double matrix2[p][q];
/**
* In following nested for loop we scan data into the array matrix2
*/
for (int i = 0; i < p; i++) {
for (int j = 0; j < q; j++) {
myfile >> matrix2[i][j];
}
}
cout << "MATRIX 2" << endl;
for (int i = 0; i < p; i++) {
for (int j = 0; j < q; j++) {
cout << right << setw(5) << matrix2[i][j];
}
cout << endl;
}
cout << endl;
/**
* Check if matrix1 and matrix2 can be added
*/
if (n == p && m == q) {
double matrix3[n][m];
for (int i = 0; i < p; i++) {
for (int j = 0; j < q; j++) {
matrix3[i][j] = matrix1[i][j] + matrix2[i][j];
}
}
cout << endl;
cout << "ADDITION of MATRIX 1 AND MATRIX 2" << endl;
for (int i = 0; i < p; i++) {
for (int j = 0; j < q; j++) {
cout << right << setw(5) << matrix3[i][j];
}
cout << endl;
}
cout << endl;
}
else {
cout << "Both matrix cannot be added!" << endl;
}
return 0;
}
const int n = 8;
const int m = 8;
These two ints are constant. That means that their value cannot be changed. They are etched in stone. They will forever contain 8, both. That's what const means in C++.
myfile >> n >> m;
This attempts to read two integer value from myfile into n and m. However, that's impossible, because we've just determined that these two variables are constant. They cannot be changed. Their values cannot be read from a file, or set in any other way.
And you cannot simply remove the const keyword either, because:
int arr[n][m];
In C++ the sizes of all arrays are fixed and they must be specified as a constant value at compile time. I surmise that you initially declared n and m to be ordinary ints, your compiler complained that you can't do this unless they are constant, you then changed them to const ints, then the compiler complained that they are not initialized, then you tried initializing them from 8, and now you cannot figure out the reason for the current compilation error.
C allows you to declare an array whose size comes from a non-constant expression at a run time, but this is not valid in C++ (although some compilers will accept this as a non-standard C++ extension).
Your C++ programming assignment requires you to do one of two things: either allocate the matrix dynamically, or use std::vectors. Either of these approaches effectively implement arrays whose size is established at runtime.
int arr[n][m];
is not being used anywhere in the code. So that can be removed.
const declarations for m, n can be replaced by the code that has been commented out
int m, n;
With these changes there shouldn't be a problem reading the dimensions of the matrix from the file. But as Sam pointed out you need to dynamically allocate the 2D arrays using malloc/new or use a std::vectorstd::vector>. You can also use boost's Matrix class - https://www.boost.org/doc/libs/1_42_0/libs/numeric/ublas/doc/matrix.htm
#include <bits/stdc++.h>
using namespace std;
const int MAX = 100;
//Function to calculate largest column
void largestInColumn(int mat[][MAX], int rows, int cols)
{
for (int i = 0; i < cols; i++) {
// initialize the maximum element with 0
int maxm = mat[0][i];
// Run the inner loop for rows
for (int j = 1; j < rows; j++) {
// check if any element is greater than the maximum element of the column and replace it
if (mat[j][i] > maxm)
maxm = mat[j][i];
}
cout << maxm << endl;
}
}
// Driver code
int main()
{
int n , m ;
cin>>n>>m;
int mat[n][m];
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>mat[i][j];
}
}
largestInColumn(mat, n, m);
return 0;
}
I will answer the question using valid C++ statements. There are no VLAs in C++. I will use a std::vector instead.
There is also no need to store any value of the matrix for this task. You can make the decision already during reading of the values.
#include <iostream>
#include <vector>
#include <limits>
int main() {
// Read number of rows and columns
if (size_t numberOfRows{}, numberOfColumns{}; std::cin >> numberOfRows >> numberOfColumns) {
// Here we will store the max values per column, so, the result
std::vector<int> maxColumnValue(numberOfColumns, std::numeric_limits<int>::lowest());
// Read all rows and columns
for (size_t row{}; row < numberOfRows; ++row)
for (size_t col{}; col < numberOfColumns; ++col)
// If the current value of the column is greater than the current max value, then use new value instead
if (int value{ std::numeric_limits<int>::lowest() }; std::cin >> value)
if (value > maxColumnValue[col]) maxColumnValue[col] = value;
// Show result to the user
for (const int m : maxColumnValue) std::cout << m << '\n';
}
return 0;
}
The cause of the error is due to you trying to pass a variable-length-array to a function that requires a standard 2D array.
First, variable-length-arrays (VLA's) are not part of standard C++. Arrays in C++ require that the sizes of the array are known at compile-time, not runtime. So pretend they don't exist, because technically, they do not exist in standard C++.
Thus you have two choices:
Declare a non-variable-size 2D array and use that, or
Use a container that is built to have dynamic size, such as std::vector.
Since you did not specify how large n could be, then solution 2 is safer.
Given that, here is your code using std::vector:
#include <vector>
#include <iostream>
using Int1D = std::vector<int>;
using Int2D = std::vector<Int1D>;
//Function to calculate largest column
void largestInColumn(Int2D& mat, int rows, int cols)
{
for (int i = 0; i < cols; i++)
{
int maxm = mat[0][i];
for (int j = 1; j < rows; j++)
{
if (mat[j][i] > maxm)
maxm = mat[j][i];
}
std::cout << maxm << std::endl;
}
}
int main()
{
int n , m ;
std::cin >> n >> m;
Int2D mat(n, Int1D(m));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
std::cin >> mat[i][j];
}
}
largestInColumn(mat, n, m);
}
Using the input:
3 3
1 2 3
1 4 9
76 34 21
The output is:
76
34
21
int Pascal_Tri(int row , int col)
{
if (row==col || col==0)
return 1 ;
else
{
return Pascal_Tri(row-1,col)+Pascal_Tri(row-1,col-1);
}
}
there is a problem with this code and I can not discover it.
when I run it, the program stops working and no results disappear
C++11
#include <iostream>
#include <vector>
std::vector<int> pascal(int height, std::vector<int> curr)
{
for(int i=0; i<curr.size(); i++)
std::cout<<curr[i]<<" ";
std::cout<<std::endl;
if(height<=0)
return curr;
std::vector<int> newCurr(curr.size()+1,1);
for(int i=0; i+1 < curr.size(); i++)
newCurr[i+1] = curr[i] + curr[i+1];
return pascal(height-1,newCurr);
}
int main()
{
int row, col;
std::cin>>row>>col;
std::vector<int> rowPascal = pascal(row,std::vector<int>{1});
std::cout<< rowPascal[col];
}
With the driver function to test. I know it's not very efficient but it should do!
This will basically give you the number at a specific row ( from the top) and a specific col (from the left) in the pascal's triangle . (both zero indexed)
Given that it's unreasonably difficult to print the triangle without using loops, here is a solution that uses your purely recursive Pascal_Tri function to compute the numbers but prints them with a loop:
int rowsToPrint = 5;
for (int row = 0; row < rowsToPrint; ++row)
{
for (int col = 0; col <= row; ++col)
std::cout << Pascal_Tri(row, col) << ", ";
std::cout << std::endl;
}
Demo
/* Program to demonstrate gaussian <strong class="highlight">elimination</strong>
on a set of linear simultaneous equations
*/
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
const double eps = 1.e-15;
/*Preliminary pivoting strategy
Pivoting function
*/
double pivot(vector<vector<double> > &a, vector<double> &b, int i)
{
int n = a.size();
int j=i;
double t=0;
for(int k=i; k<n; k+=1)
{
double aki = fabs(a[k][i]);
if(aki>t)
{
t=aki;
j=k;
}
}
if(j>i)
{
double dummy;
for(int L=0; L<n; L+=1)
{
dummy = a[i][L];
a[i][L]= a[j][L];
a[j][L]= dummy;
}
double temp = b[j];
b[i]=b[j];
b[j]=temp;
}
return a[i][i];
}
/* Forward <strong class="highlight">elimination</strong> */
void triang(vector<vector<double> > &a, vector<double> &b)
{
int n = a.size();
for(int i=0; i<n-1; i+=1)
{
double diag = pivot(a,b,i);
if(fabs(diag)<eps)
{
cout<<"zero det"<<endl;
return;
}
for(int j=i+1; j<n; j+=1)
{
double mult = a[j][i]/diag;
for(int k = i+1; k<n; k+=1)
{
a[j][k]-=mult*a[i][k];
}
b[j]-=mult*b[i];
}
}
}
/*
DOT PRODUCT OF TWO VECTORS
*/
double dotProd(vector<double> &u, vector<double> &v, int k1,int k2)
{
double sum = 0;
for(int i = k1; i <= k2; i += 1)
{
sum += u[i] * v[i];
}
return sum;
}
/*
BACK SUBSTITUTION STEP
*/
void backSubst(vector<vector<double> > &a, vector<double> &b, vector<double> &x)
{
int n = a.size();
for(int i = n-1; i >= 0; i -= 1)
{
x[i] = (b[i] - dotProd(a[i], x, i + 1, n-1))/ a[i][i];
}
}
/*
REFINED GAUSSIAN <strong class="highlight">ELIMINATION</strong> PROCEDURE
*/
void gauss(vector<vector<double> > &a, vector<double> &b, vector<double> &x)
{
triang(a, b);
backSubst(a, b, x);
}
// EXAMPLE MAIN PROGRAM
int main()
{
int n;
cin >> n;
vector<vector<double> > a;
vector<double> x;
vector<double> b;
for (int i = 0; i < n; i++) {
vector<double> temp;
for (int j = 0; j < n; j++) {
int no;
cin >> no;
temp.push_back(no);
}
a.push_back(temp);
b.push_back(0);
x.push_back(0);
}
/*
for (int i = 0; i < n; i++) {
int no;
cin >> no;
b.push_back(no);
x.push_back(0);
}
*/
gauss(a, b, x);
for (size_t i = 0; i < x.size(); i++) {
cout << x[i] << endl;
}
return 0;
}
The above gaussian eleimination algorithm works fine on NxN matrices. But I need it to work on NxM matrix. Can anyone help me to do it? I am not very good at maths. I got this code on some website and i am stuck at it.
(optional) Understand this. Do some examples on paper.
Don't write code for Gaussian elimination yourself. Without some care, the naive gauss pivoting is unstable. You have to scale the lines and take care of pivoting with the greatest element, a starting point is there. Note that this advice holds for most linear algebra algorithms.
If you want to solve systems of equations, LU decomposition, QR decomposition (stabler than LU, but slower), Cholesky decomposition (in the case the system is symmetric) or SVD (in the case the system is not square) are almost always better choices. Gaussian elimination is best for computing determinants however.
Use the algorithms from LAPACK for the problems which need Gaussian elimination (eg. solving systems, or computing determinants). Really. Don't roll your own. Since you are doing C++, you may be interested in Armadillo which takes care of a lot of things for you.
If you must roll your own for pedagogical reasons, have a look first at Numerical Recipes, version 3. Version 2 can be found online for free if you're low on budget / have no access to a library.
As a general advice, don't code algorithms you don't understand.
You just cannot apply Gaussian elimination directly to an NxM problem. If you have more equations than unknowns, the your problem is over-determined and you have no solution, which means you need to use something like the least squares method. Say that you have A*x = b, then instead of having x = inv(A)*b (when N=M), then you have to do x = inv(A^T*A)*A^T*b.
In the case where you have less equations then unknowns, then your problem is underdetermined and you have an infinity of solutions. In that case, you either pick one at random (e.g. setting some of the unknowns to an arbitrary value), or you need to use regularization, which means trying adding some extra constraints.
You can apply echelon reduction, like in this snippet
#include <iostream>
#include <algorithm>
#include <vector>
#include <iomanip>
using namespace std;
/*
A rectangular matrix is in echelon form(or row echelon form) if it has the following
three properties :
1. All nonzero rows are above any rows of all zeros.
2. Each leading entry of a row is in a column to the right of the leading entry of
the row above it.
3. All entries in a column below a leading entry are zeros.
If a matrix in echelon form satisfies the following additional conditions,
then it is in reduced echelon form(or reduced row echelon form) :
4. The leading entry in each nonzero row is 1.
5. Each leading 1 is the only nonzero entry in its column.
*/
template <typename C> void print(const C& c) {
for (const auto& e : c) {
cout << setw(10) << right << e;
}
cout << endl;
}
template <typename C> void print2(const C& c) {
for (const auto& e : c) {
print(e);
}
cout << endl;
}
// input matrix consists of rows, which are vectors of double
vector<vector<double>> Gauss::Reduce(const vector<vector<double>>& matrix)
{
if (matrix.size() == 0)
throw string("Empty matrix");
auto A{ matrix };
auto mima = minmax_element(A.begin(), A.end(), [](const vector<double>& a, const vector<double>& b) {return a.size() < b.size(); });
auto mi = mima.first - A.begin(), ma = mima.second - A.begin();
if (A[mi].size() != A[ma].size())
throw string("All rows shall have equal length");
size_t height = A.size();
size_t width = A[0].size();
if (width == 0)
throw string("Only empty rows");
for (size_t row = 0; row != height; row++) {
cout << "processing row " << row << endl;
// Search for maximum below current row in column row and move it to current row; skip this step on the last one
size_t col{ row }, maxRow{ 0 };
// find pivot for current row (partial pivoting)
while (col < width)
{
maxRow = distance(A.begin(), max_element(A.begin() + row, A.end(), [col](const vector<double>& rowVectorA, const vector<double>& rowVectorB) {return abs(rowVectorA[col]) < abs(rowVectorB[col]); }));
if (A[maxRow][col] != 0) // nonzero in this row and column or below found
break;
++col;
}
if (col == width) // e.g. in current row and below all entries are zero
break;
if (row != maxRow)
{
swap(A[row], A[maxRow]);
cout << "swapped " << row << " and " << maxRow;
}
cout << " => leading entry in column " << col << endl;
print2(A);
// here col >= row holds; col is the column of the leading entry e.g. first nonzero column in current row
// moreover, all entries to the left and below are zeroed
if (row+1 < height)
cout << "processing column " << col << endl;
// Make in all rows below this one 0 in current column
for (size_t rowBelow = row + 1; rowBelow < height; rowBelow++) {
// subtract product of current row by factor
double factor = A[rowBelow][col] / A[row][col];
cout << "processing row " << rowBelow << " below the current; factor is " << factor << endl;
if (factor == 0)
continue;
for (size_t colRight{ col }; colRight < width; colRight++)
{
auto d = A[rowBelow][colRight] - factor * A[row][colRight];
A[rowBelow][colRight] = abs(d) < DBL_EPSILON ? 0 : d;
}
print(A[rowBelow]);
}
}
// the matrix A is in echelon form now
cout << "matrix in echelon form" << endl;
print2(A);
// reduced echelon form follows (backward phase)
size_t row(height-1);
auto findPivot = [&row, A] () -> size_t {
do
{
auto pos = find_if(A[row].begin(), A[row].end(), [](double d) {return d != 0; });
if (pos != A[row].end())
return pos - A[row].begin();
} while (row-- > 0);
return A[0].size();
};
do
{
auto col = findPivot();
if (col == width)
break;
cout << "processing row " << row << endl;
if (A[row][col] != 1)
{
//scale row row to make element at [row][col] equal one
auto f = 1 / A[row][col];
transform(A[row].begin()+col, A[row].end(), A[row].begin()+col, [f](double d) {return d * f; });
}
auto rowAbove{ row};
while (rowAbove > 0)
{
rowAbove--;
double factor = A[rowAbove][col];
if (abs(factor) > 0)
{
for (auto colAbove{ 0 }; colAbove < width; colAbove++)
{
auto d = A[rowAbove][colAbove] - factor * A[row][colAbove];
A[rowAbove][colAbove] = abs(d) < DBL_EPSILON ? 0 : d;
}
cout << "transformed row " << rowAbove << endl;
print(A[rowAbove]);
}
}
} while (row-- > 0);
return A;
}