C++ strange class declaration - c++

I'm practicing ACM problems to become a better programmer, but I'm still fairly new to c++ and I'm having trouble interpreting some of the judges code I'm reading. The beginning of a class starts with
public:
State(int n) : _n(n), _p(2*n+1)
{
and then later it's initialized with
State s(n);
s(0,0) = 1;
I'm trying to read the code but I can't make sense of that. The State class only seems to have 1 argument passed, but the programmer is passing 2 in his initialization. Also, what exactly is being set = to 1? As far as I can tell, the = operator isn't being overloaded but just in case I missed something I've included the full code below.
Any help would be greatly appreciated.
Thanks in advance
/*
* D - Maximum Random Walk solution
* ICPC 2012 Greater NY Regional
* Solution by Adam Florence
* Problem by Adam Florence
*/
#include <cstdio> // for printf
#include <cstdlib> // for exit
#include <algorithm> // for max
#include <iostream>
#include <vector>
using namespace std;
class State
{
public:
State(int n) : _n(n), _p(2*n+1)
{
if (n < 1)
{
cout << "Ctor error, n = " << n << endl;
exit(1);
}
for (int i = -n; i <= n; ++i)
_p.at(i+_n) = vector<double>(n+1, 0.0);
}
void zero(const int n)
{
for (int i = -n; i < n; ++i)
for (int m = 0; m <= n; ++m)
_p[i+_n][m] = 0;
}
double operator()(int i, int m) const
{
#ifdef DEBUG
if ((i < -_n) || (i > _n))
{
cout << "Out of range error, i = " << i << ", n = " << _n << endl;
exit(1);
}
if ((m < 0) || (m > _n))
{
cout << "Out of range error, m = " << m << ", n = " << _n << endl;
exit(1);
}
#endif
return _p[i+_n][m];
}
double& operator()(int i, int m)
{
#ifdef DEBUG
if ((i < -_n) || (i > _n))
{
cout << "Out of range error, i = " << i << ", n = " << _n << endl;
exit(1);
}
if ((m < 0) || (m > _n))
{
cout << "Out of range error, m = " << m << ", n = " << _n << endl;
exit(1);
}
#endif
return _p[i+_n][m];
}
static int min(int x, int y)
{
return(x < y ? x : y);
}
static int max(int x, int y)
{
return(x > y ? x : y);
}
private:
int _n;
// First index is the current position, from -n to n.
// Second index is the maximum position so far, from 0 to n.
// Value is probability.
vector< vector<double> > _p;
};
void go(int ds)
{
// Read n, l, r
int n, nds;
double l, r;
cin >> nds >> n >> l >> r;
const double c = 1 - l - r;
if(nds != ds){
cout << "Dataset number " << nds << " does not match " << ds << endl;
return;
}
// Initialize state, probability 1 at (0,0)
State s(n);
s(0,0) = 1;
State t(n);
State* p1 = &s;
State* p2 = &t;
for (int k = 1; k <= n; ++k)
{
// Compute probabilities at step k
p2->zero(k);
// At step k, the farthest from the origin you can be is k
for (int i = -k; i <= k; ++i)
{
const int mm = State::min( State::max(0, i+k), k);
for (int m = 0; m <= mm; ++m)
{
// At step k-1, p = probability of (i,m)
const double p = p1->operator()(i,m);
if (p > 0)
{
// Step left
p2->operator()(i-1, m) += p*l;
// Step right
p2->operator()(i+1, State::max(i+1,m)) += p*r;
// Stay put
p2->operator()(i, m) += p*c;
}
}
}
swap(p1, p2);
}
// Compute expected maximum position
double p = 0;
for (int i = -n; i <= n; ++i)
for (int m = 0; m <= n; ++m)
p += m * p1->operator()(i,m);
printf("%d %0.4f\n", ds, p);
}
int main(int argc, char* argv[])
{
// Read number of data sets to process
int num;
cin >> num;
// Process each data set identically
for (int i = 1; i <= num; ++i)
go(i);
// We're done
return 0;
}

You are confusing a call to state::operator()(int, int) with an initialization. That operator call lets you set the value of an element of the class instance.
State s(n); // this is the only initialization
s(0,0) = 1; // this calls operator()(int, int) on instance s

In this line:
s(0,0) = 1;
it's calling this:
double& operator()(int i, int m)
and because it returns a reference to a double, you can assign to it.

The second line is no longer initialization. The constructor was invoked in line 1, the second line invokes
double& operator()(int i, int m)
with n=0 and m=0 and writing 1 to the reference that is returned.

This part:
State(int n) : _n(n), _p(2*n+1)
...is a member initializer list. It's sort of similar to if you'd written the construct like:
state(int n) { _n = n; _p = 2*n+1; }
...except that it initializes _n and _p instead of starting with them unitialized, then assigning values to them. In this specific case that may not make much difference, but when you have things like references that can only be initialized (not assigned) it becomes crucial.
The s(0,0) = 1 looks like s is intended to act a little like a 2D array, and they've overloaded operator() to act as a subscripting operator for that array. I posted a class that does that in a previous answer.

Related

What's wrong in this code , it's doing nothing other than taking inputs of n and m

Here in this question the function call is not executing also tell me abut can't I use array instead of vectors here.
if Possible to use array please provide me with code that how to pass arrays to a function in c++
Here in this question the function call is not executing also tell me abut can't I use array instead of vectors here.
if Possible to use array please provide me with code that how to pass arrays to a function in c++
#include <iostream>
#include <vector>
using namespace std;
int recursion(vector<vector<int>> &v, int n, int m)
{
if (n == 0 && m == 0)
{
return v[n][m];
}
int left = v[n][m] + recursion(v, n - 1, m);
int right = v[n][m] + recursion(v, n, m - 1);
return min(left, right);
}
int main()
{
int n, m;
cout << "enter the value of n and m" << endl;
cin >> n >> m;
cout << n << m;
//it's doing nothing after this point.
vector<vector<int>> vec(n, vector<int>(m));
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= m; j++)
{
vec[i][j] = (i)*m + (j + 1);
}
}
int result = recursion(vec, n, m);
cout << result;
return 0;
}
vec[i][j] = (i)*m + (j + 1);
is out-of-bounds for i = n and j = m. Same problem with calling recursion(vec, n, m);

How to declare arrays which are functions argument, if their size is to be determined by the user input at the start of program

For my "basics of programming" project i was ordered to make a "memory game". 2 players in their respective turns choose which cards to reveal on a "m x n" sized board. "m" and "n" are to be chosen at the start of each game. My question is, how can I create an array of structures used to display the board a the moment of user's input. So far I just used a const int to create an array of a maximum size, however more than 95% of the arrays indexes are empty using this method. Is there a way to create the array right after user's input while also having those functions defined and declared with an array of structures that's the size of the input? Here's my code so far:
const int MAX_M = 1000;
const int MAX_N = 1000;
Karta Plansza2[MAX_M][MAX_N];
void SprawdzanieParzystosci(int& m, int& n);
void RozmiaryTablicy(int& m, int& n);
void generuj(int m, int n, Karta Plansza[MAX_M][MAX_N]);
void WyswietleniePlanszy(int m, int n, Karta Plansza[MAX_M][MAX_N]);
void generuj(int m, int n, Karta Plansza[][MAX_N])
{
srand((unsigned int)time(NULL));
char A;
int B;
int C;
int D;
int k = 0;
int w1, w2, k1, k2;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
Plansza[i][j].WartoscKarty = 0;
}
while (k < (m*n))
{
A = char(rand() % 10 + 65);
B = (rand() % 10);
C = (rand() % 10);
D = ((rand() % 2000000) + 1);
do{
w1 = rand() % m;
k1 = rand() % n;
}while(Plansza[w1][k1].WartoscKarty != 0);
Plansza[w1][k1].ZnakPierwszy = A;
Plansza[w1][k1].LiczbaPierwsza = B;
Plansza[w1][k1].LiczbaDruga = C;
Plansza[w1][k1].WartoscKarty = D;
k++;
do{
w2 = rand() % m;
k2 = rand() % n;
} while (Plansza[w2][k2].WartoscKarty != 0);
Plansza[w2][k2].ZnakPierwszy = A;
Plansza[w2][k2].LiczbaPierwsza = B;
Plansza[w2][k2].LiczbaDruga = C;
Plansza[w2][k2].WartoscKarty = D;
k++;
}
}
/////////////////////////////////////////////////////
void WyswietleniePlanszy(int m, int n, Karta Plansza[MAX_M][MAX_N])
{
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++)
cout << "***" << setw(5);
cout << "\n";
for (int j = 0; j < n; j++)
cout << "*" << Plansza[i][j].ZnakPierwszy << "*" << " ";
cout << "\n";
for (int j = 0; j < n; j++)
cout << "*" << Plansza[i][j].LiczbaPierwsza << "*" << " ";
cout << "\n";
for (int j = 0; j < n; j++)
cout << "*" << Plansza[i][j].LiczbaDruga << "*" << " ";
cout << "\n";
// for(int j = 0; j < 10; j++)
// cout << wzor[i][j].num4 << " ";
for (int j = 0; j < n; j++)
cout << "***" << setw(5);
cout << "\n";
cout << endl;
}
}
/////////////////////////////////////////////////////
void RozmiaryTablicy(int& m, int& n)
{
cout << "Podaj rozmiar m tablicy: ";
cin >> m;
cout << "Podaj rozmiar n tablicy: ";
cin >> n;
}
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
void SprawdzanieParzystosci(int& m, int& n)
{
while ((m * n) % 2 != 0 || (m <= 0) || (n <= 0)) {
RozmiaryTablicy(m, n);
if((m * n) % 2 != 0 || (m <= 0) || (n <= 0)) cout << "Zle dane. Prosze podac dane jeszcze raz" << endl;
}
}
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
int main()
{
int m =1;
int n =1;
SprawdzanieParzystosci(m, n);
generuj(m,n,Plansza2);
WyswietleniePlanszy(m,n,Plansza2);
cout << m << endl;
cout << n << endl;
system("pause");
return 0;
}
For example, If the user inputs m = 5 an n = 6 it would create an Plansza[5][6] array instead of a Plansza[1000][1000] array
Quick hack of a board, remark the nice board[row][column] notation and the returned reference to the field. C++17 (might work in C++14)
#include <iostream>
#include <memory>
#include <cstring>
using DaType = char;
class Board {
int rows = 0;
int cols = 0;
std::unique_ptr<DaType[]> board; // RAII
public:
class Row {
DaType *board;
public:
Row(DaType *row) : board(row) {}
DaType& operator[](int col) { return board[col]; }
};
Board(int row, int col) : rows(row), cols(col), board(std::make_unique<DaType[]>(row*col)) { memset(board.get(), '.', rows*cols); }
Row operator[](int row) { return Row(board.get()+row*cols); }
};
int main() {
const int sx = 6, sy = 10;
Board board(sx,sy);
board[3][5] = 'x';
for (int i = 0; i < sx; ++i ) {
for (int j = 0; j < sy; ++j )
std::cout << board[i][j];
std::cout << '\n';
}
}
Ps. it seemed simpler last time I did this ...
Update thanks to IlCapitano
class Board {
int rows = 0;
int cols = 0;
std::unique_ptr<DaType[]> board; // RAII
public:
Board(int row, int col) : rows(row), cols(col), board(std::make_unique<DaType[]>(row*col)) { memset(board.get(), '.', rows*cols); }
DaType *operator[](int row) { return board.get()+row*cols; }
};
The easiest way to solve this would be to just use std::vector, since the size of arrays in arguments, stackallocations, etc. has to be known at compile-time.
The easiest option without using vector would be to declare Plansza2 as a Karta* and allocate the memory dynamically after SprawdzanieParzystosci using Plansza2 = new Karta[m*n]; (Don't forget to call delete[](Plansza2); before ending your program). If you do this you can access the cells with Plansza2[y * m + x] (assuming m is width and n is height). The advantage of mapping the 2-dimensional array to a 1 dimensional array by placing all rows after one another is that you only need one allocation and one deletion, and furthermore it improves cache-friendliness.
A cleaner way to solve this (removing the possibility for a memory leak if something throws an exception or you forget to call delete) would be to create your own class for 2-dimensional arrays, that would call new[] in the constructor and delete[] in the destructor. If you do that you could define Karta& operator()(int x, int y); and const Karta& operator()(int x, int y) const; to return the appropriate cell, allowing you to access a cell with dynamicMap(x, y). operator[] can only take one argument and is therefor more complicated to use to access a 2-dimensional array (you can for example take an std::pair as the argument or return a proxy-class that also has operator[] defined). However if you write your own destructor, you need to take care of the copy-(always) and move-(c++11 onwards) constructors and assignment operators, since the default instantiations would lead to your destructor trying to delete the same pointer multiple times. An example for a move-assignment operator is:
DynamicMap& DynamicMap::operator=( DynamicMap&& map ){
if(this == &map)
return *this; //Don't do anything if both maps are the same map
dataPointer = map.dataPointer; //Copy the pointer to "this"
map.dataPointer = nullptr; //Assign nullptr to map.dataPointer because delete[] does nothing if called with null as an argument
//You can move other members in the above fashion, using std::move for types more complex than a pointer or integral, but be careful to leave map in a valid, but empty state, so that you do not try to free the same resource twice.
return *this;
}
The move constructor doesn't require the if-clause at the start, but is otherwise identical and the copy-constructor/assignment operator should probably declared as = delete; since it will probably be a bug if you copy your map. If you do need to define the copy operations, do not copy the pointer but instead create a new array and copy the contents.

Operator*= from two instances (Matrix) gives bad results

I have a class Matrix, and I'm trying to implement the method operator*=, which i use to make the product of two instances(matrix): m1*=m2.
I tried both method with friend and two parameter, and without friend and 1 parameter, but in both cases the results it's bad. Only with one parameter and the this use gives me results similar to the right (not always).
Tried with friend and 2 parameter, and without friend and 1 parameter. Tried returning directly the first matrix, m1, also creating a temporary matrix m3
My private members:
int N, M;
T** data;
bool Init(const int N_, const int M_);
void Clear();
(i'm using init to initialize the matrix/bidimensional array):
bool Matrix::Init(const int N_, const int M_) {
this->Clear(); //dealloco comunque prima di inizializzarla
N = N_;
M = M_;
if (N <= 0 || M <= 0) {
cerr << "Non posso generare una matrixe: " << N <<"x"<< M << endl;
return false;
}
else if (N > 0 && M > 0) {
data = new T*[N];
for (int i = 0; i < N; i++) {
data[i] = new T[M];
}
}
return true;
}
My operator *= mathod (no friend, 1 parameter):
Matrix& Matrix::operator*=(const Matrix& m2) {
float operation = 0;
int N_ = (this->N < m2.N) ? this->N : m2.N;
int M_ = (this->M < m2.M) ? this->M : m2.M;
Matrix m3(N_, M_);
if (this->N != m2.M || this->M != m2.N) {
this->Set(0, 0, flag_stop);
}
else {
for (int i = 0; i < this->N; ++i) {
for (int j = 0; j < m2.M; ++j) {
for (int k = 0; k < this->M; ++k) {
operation = operation + (this->Get(i,k) * m2.Get(k,j)) ;
//cout << " Cout m1 su "<< i<< ","<<k<<":"<< this->Get(i,k) << "\t " << " Cout m2: "<< m2.Get(k,j) << endl;
this->Set(i, j, operation);
}
//cout << operation << "\t";
operation = 0;
}
operation = 0;
}
}
return *this;
}
In the main, when i try to use the operator*=:
Matrix m1(i1,j1);
Matrix m2(i2,j2);
//operator*=
cout << endl;
m1*=m2;
int N_ = (m1.GetN() < m2.GetN()) ? m1.GetN() : m2.GetN();
int M_ = (m1.GetM() < m2.GetM()) ? m1.GetM() : m2.GetM();
for (int i = 0; i < N_; ++i) {
for (int j = 0; j < M_; ++j) {
cout << m1.Get(i,j) << "\t";
}
cout << endl;
}
It's all the day that i try, but the results are not rights
i also tried with m1[2][2] and m2[2][2], with m1[3][2] and m2[2][3], etc... but nothing. Someone have had a similar problem?
Hoping to have right product of two matrixes, but i have, at the major times, big numbers (expected 5, obtained 30), or the first column right numbers, and the second not
The reason for mistakes you report seems to be the multiplication algorithm itself. Basically, your multiplication code is as follows:
for (int i = 0; i < this->N; ++i) {
for (int j = 0; j < m2.M; ++j) {
for (int k = 0; k < this->M; ++k) {
operation = operation + (this->Get(i,k) * m2.Get(k,j)) ;
this->Set(i, j, operation);
}
operation = 0;
}
}
Your algorithm modifies the original matrix just in the process of the calculation (this->Set() call) so when you call this->Get(i,k) for any i < j you obtain not an original value of the first matrix at ith row and kth column but a value that was already modified by this->Set() call. This apparently leads to wrong results.
In order to solve this you must ensure that you use original matrix values for your calculations, for example, by making a copy of the original matrix or (more optimal) of the currently modified row of the original matrix.

C++ Bin Packing Implementation using First Fit

I'm doing a project for university but I encountered an exception which I don't understand. I'm using S.Sahni algorithms, so mostly I've got the code from his book. What I'm trying to do is to implement the Bin Packing problem with First Fit while I'm using tournament trees (max winner).
Here is my header:
// file winner.h
#ifndef WinnerTree_
#define WinnerTree_
#include <iostream>
#include <stdlib.h>
#include "xcept.h"
using namespace std;
template<class T>
class WinnerTree {
public:
WinnerTree(int TreeSize = 10);
~WinnerTree() {delete [] t;}
void Initialize(T a[], int size, int (&winner)(T a[], int player1, int player2));
int Winner()
{return (n) ? t[1] : 0;}
int Winner(int i)
{return (i < n) ? t[i] : 0;}
void RePlay(int i, int (&winner)(T a[], int player1, int player2));
void Output();
private:
int MaxSize;
int n; // current size
int LowExt; // lowest-level external nodes
int offset; // 2^k - 1
int *t; // array for winner tree
T *e; // element array
void Play(int p, int lc, int rc, int (&winner)(T a[], int player1, int player2));
};
template<class T>
WinnerTree<T>::WinnerTree(int TreeSize)
{// Constructor for winner tree.
MaxSize = TreeSize;
t = new int[MaxSize];
n = 0;
}
template<class T>
void WinnerTree<T>::Initialize(T a[], int size, int (&winner)(T a[], int player1, int player2))
{// Initialize winner t for array a.
if (size > MaxSize || size < 2)
throw BadInput();
n = size;
e = a;
// compute s = 2^log (n-1)
int i, s;
for (s = 1; 2*s <= n-1; s += s);
LowExt = 2*(n-s);
offset = 2*s-1;
// play matches for lowest-level external nodes
for (i = 2; i <= LowExt; i += 2)
Play((offset+i)/2, i-1, i, winner);
// handle remaining external nodes
if (n % 2) {// special case for odd n, play
// internal and external node
Play(n/2, t[n-1], LowExt+1, winner);
i = LowExt+3;}
else
i = LowExt+2;
// i is left-most remaining external node
for (; i <= n; i += 2)
Play((i-LowExt+n-1)/2, i-1, i, winner);
}
template<class T>
void WinnerTree<T>::Play(int p, int lc, int rc, int (&winner)(T a[], int player1, int player2))
{// Play matches beginning at t[p].
// lc and rc are the children of t[p].
t[p] = winner(e, lc, rc);
// more matches possible if at right child
while (p > 1 && p % 2) {// at a right child
t[p/2] = winner(e, t[p-1], t[p]);
p /= 2; // go to parent
}
}
template<class T>
void WinnerTree<T>::RePlay(int i, int(&winner)(T a[], int player1, int player2))
{// Replay matches for element i.
if (i <= 0 || i > n)
throw OutOfBounds();
int p, // match node
lc, // left child of p
rc; // right child of p
// find first match node and its children
if (i <= LowExt) {// begin at lowest level
p = (offset + i)/2;
lc = 2*p - offset; // left child of p
rc = lc+1;}
else {
p = (i-LowExt+n-1)/2;
if (2*p == n-1) {
lc = t[2*p];
rc = i;}
else {
lc = 2*p - n + 1 + LowExt;
rc = lc+1;}
}
t[p] = winner(e, lc, rc);
// play remaining matches
p /= 2; // move to parent
for (; p >= 1; p /= 2)
t[p] = winner(e, t[2*p], t[2*p+1]);
}
template<class T>
void WinnerTree<T>::Output()
{
cout << "size = "<< n << " LowExt = " << LowExt
<< " Offset = " << offset << endl;
cout << "Winner tree pointers are" << endl;
for (int i = 1; i < n; i++)
cout << t[i] << ' ';
cout << endl;
}
#endif
This is my exception file:
#ifndef Xcept_
#define Xcept_
#include <exception>
#include <new.h>
// bad initializers
class BadInitializers {
public:
BadInitializers() {}
};
// insufficient memory
class NoMem {
public:
NoMem() {}
};
// change new to throw NoMem instead of xalloc
void my_new_handler()
{
throw NoMem();
};
new_handler Old_Handler_ = set_new_handler(my_new_handler);
// improper array, find, insert, or delete index
// or deletion from empty structure
class OutOfBounds {
public:
OutOfBounds() {}
};
// use when operands should have matching size
class SizeMismatch {
public:
SizeMismatch() {}
};
// use when zero was expected
class MustBeZero {
public:
MustBeZero() {}
};
// use when zero was expected
class BadInput {
public:
BadInput() {}
};
#endif
And this is my main function:
// First fit bin packing
#include "stdafx.h"
using namespace std;
#include <iostream>
#include "winner.h"
int winner(int a[], int player1, int player2)
{// For a max winner tree.
if (a[player1] >= a[player2])
return player1;
return player2;
}
void FirstFitPack(int s[], int n, int c)
{// Output first fit packing into bins of size c.
// n is the number of objects and s[] their size.
WinnerTree<int> *W = new WinnerTree<int>(n);
int *avail = new int[n + 1]; // bins
// initialize n bins and winner tree
for (int i = 1; i <= n; i++)
avail[i] = c; // initial available capacity
W->Initialize(avail, n, winner);
// put objects in bins
for (int i = 1; i <= n; i++) {// put s[i] in a bin
// find first bin with enough capacity
int p = 2; // start search at left child of root
while (p < n) {
int winp = W->Winner(p);
if (avail[winp] < s[i]) // first bin is in
p++; // right subtree
p *= 2; // move to left child
}
int b; // will be set to bin to use
p /= 2; // undo last left child move
if (p < n) {// at a tree node
b = W->Winner(p);
// if b is right child, need to check
// bin b-1. No harm done by checking
// bin b-1 even if b is left child.
if (b > 1 && avail[b - 1] >= s[i])
b--;
}
else // arises when n is odd
b = W->Winner(p / 2);
cout << "Pack object " << i << " in bin "
<< b << endl;
avail[b] -= s[i]; // update avail. capacity
W->RePlay(b, winner);
getchar();
}
}
int main(void)
{
int n, c; // number of objects and bin capacity
cout << "Enter number of objects" << endl;
cin >> n;
if (n < 2) {
cout << "Too few objects" << endl;
exit(1);
}
cout << "Enter bin capacity" << endl;
cin >> c;
int *s = new int[n + 1];
for (int i = 1; i <= n; i++) {
cout << "Enter space requirement of object " << i << endl;
cin >> s[i];
if (s[i] > c) {
cout << "Object too large to fit in a bin" << endl;
exit(1);
}
}
FirstFitPack(s, n, c);
return 0;
}
The exception that I get is:
First-chance exception at 0x0012668D in Bin Packing-FF.exe: 0xC0000005: Access violation reading location 0xF9039464.
I know that I'm getting this exception because of the winner. But I can't understand what I have to change here.
int winner(int a[], int player1, int player2)
{// For a max winner tree.
if (a[player1] >= a[player2])
return player1;
return player2;
}
Also, If I press space or enter after the last input (object) then I don't get the exception and everything is going smoothly. But still I want to know why I'm getting this exception.
Thank you in advance.

Gauss Elimination for NxM matrix

/* 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;
}