Create multiple objects for a simulation - c++

Basically I wrote code to simulate one encoded data vector over a AWGN channel. The simulation but only works once. So I would like to create multiple objects or find a way to run the code multiple times depending on int N (for example int N = 1000000; in my case), so that I can calculate the BER (bit error rate).
I haven't found an elegant way to do that yet though...
I hope you understand my question.
Do you need more information?
Thank you!!
#include <iostream>
#include "encode.h"
#include "awgn.h"
#include "decode.h"
using namespace Eigen;
int main()
{
std::string code = "Hamming";
int dim_u, dim_mat_col, dim_mat_row, dim_mat_col_H, dim_mat_row_H;
MatrixXi P;
if (code == "Hamming")
{
dim_u = 4; // can also call it "k"
dim_mat_col = 7; // also serves as dim of x and y, or simply n
dim_mat_row = 4;
dim_mat_col_H = dim_mat_col;
dim_mat_row_H = dim_mat_col - dim_mat_row;
P = MatrixXi::Zero(dim_u, dim_mat_col - dim_u);
P << 1, 1, 0,
0, 1, 1,
1, 1, 1,
1, 0, 1;
}
if (code == "BCH")
{
dim_u = 7;
dim_mat_col = 15; // also serves as dim of x and y, or simply n
dim_mat_row = 7;
dim_mat_col_H = dim_mat_col;
dim_mat_row_H = dim_mat_col - dim_mat_row;
P = MatrixXi::Zero(dim_u, dim_mat_col - dim_u);
P << 1, 1, 1, 0, 1, 0, 0, 0,
0, 1, 1, 1, 0, 1, 0, 0,
0, 0, 1, 1, 1, 0, 1, 0,
0, 0, 0, 1, 1, 1, 0, 1,
1, 1, 1, 0, 0, 1, 1, 0,
0, 1, 1, 1, 0, 0, 1, 1,
1, 1, 0, 1, 0, 0, 0, 1;
}
if (code == "Golay")
{
dim_u = 12;
dim_mat_col = 24; // also serves as dim of x and y, or simply n
dim_mat_row = 12;
dim_mat_col_H = dim_mat_col;
dim_mat_row_H = dim_mat_col - dim_mat_row;
P = MatrixXi::Zero(dim_u, dim_mat_col - dim_u);
P << 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1,
0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0,
0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1,
1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0,
1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1,
1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0,
1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1,
1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0,
0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1,
0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1;
}
int N = 1000000; // number of simulations
bool c_hat_minus_c = 0;
int val = 0;
Encode vec(dim_u, dim_mat_row, dim_mat_col);
awgn channel(dim_mat_col);
Decode dec(dim_mat_col, dim_mat_row_H, dim_mat_col_H, P);
vec.encodeDataVector(dim_u, dim_mat_col, P);
// std::cout << "modulated x: " << vec.x << std::endl;
channel.addGausian(vec.x);
// std::cout << channel.y << std::endl;
c_hat_minus_c = dec.decodingalg(6000, channel.y, P, vec.x); // check if codeword is received correctly
// std::cout << channel.y << std::endl;
// std::cout << "val: " << val << std::endl;
}
If I wrap the stack allocated objects in a for loop like this:
for (int i = 0; i < N; i++)
{
Encode vec(dim_u, dim_mat_row, dim_mat_col);
awgn channel(dim_mat_col);
Decode dec(dim_mat_col, dim_mat_row_H, dim_mat_col_H, P);
vec.encodeDataVector(dim_u, dim_mat_col, P);
// std::cout << "modulated x: " << vec.x << std::endl;
channel.addGausian(vec.x);
// std::cout << channel.y << std::endl;
c_hat_minus_c = dec.decodingalg(6000, channel.y, P, vec.x); // check if codeword is received correctly
// std::cout << channel.y << std::endl;
// std::cout << "val: " << val << std::endl;
}
The program breaks and says:
/usr/include/eigen3/Eigen/src/Core/CommaInitializer.h:97: Eigen::CommaInitializer& Eigen::CommaInitializer::operator,(const Eigen::DenseBase&) [with OtherDerived = Eigen::Matrix<int, -1, -1>; XprType = Eigen::Matrix<int, -1, -1>]: Assertion `(m_col + other.cols() <= m_xpr.cols()) && "Too many coefficients passed to comma initializer (operator<<)"' failed.
Edit:
so I basically found out that it braks in encode.cpp
the second time it tries to initialize the Matrix G_
#include <iostream>
#include "encode.h"
#include "awgn.h"
#include <cstdlib> // rand and srand
#include <ctime> // For the time function
using namespace std;
using namespace Eigen;
Encode::Encode(int dim_u, int dim_mat_row, int dim_mat_col) //(7,4) Hamming code only up to now
{
// if (code == "Hamming")
// dim_u = 4;
// dim_mat_col = 7;
// dim_mat_row = 4;
u_ = RowVectorXi::Zero(dim_u);
G_ = MatrixXi::Zero(dim_mat_row, dim_mat_col);
}
void Encode::encodeDataVector(int dim_u, int dim_mat_col, MatrixXi &P)
{
// Get the system time.
unsigned seed = time(0);
// Seed the random number generator.
srand(seed);
for (int i = 0; i < dim_u; i++)
{
u_(i) = rand() % 2; // only zeros and ones
}
// cout << u_ << endl << endl;
MatrixXi I;
// I = MatrixXi::Zero(7, 7);
I = MatrixXi::Identity(dim_u, dim_u);
G_ << I, P; **<----- here**
// cout << G_ << endl << endl;
x = u_ * G_;
for (int i = 0; i < dim_mat_col; i++)
{
x(i) = x(i) % 2;
}
// std::cout << "correct codeword: " << x << std::endl;
// mapping for BPSK
for (int i = 0; i < dim_mat_col; i++)
{
if (x(i) == 0)
x(i) = 1;
else
x(i) = -1;
}
// awgn::awgn channel(dim_mat_col);
// channel.addGausian(this->x);
}

P is being passed by non-const reference, which means it may be modified by the functions you call. Passing a copy of P in each iteration makes sure that the modifications to P stay local to that iteration:
for (int i = 0; i < N; i++) {
MatrixXi P_copy = P;
...
}

Related

Unable to get BFS algorithm to work properly in c++

I'm creating a dungeon/rouge-like game in c++ and am trying to implement pathfinding.
The issue I am having is that when the player moves more than two times the adjacency matrix doesn't generate properly. What happens is that every place that the player has been turning to a zero which signifies that you cant go there. I am trying to regenerate the matrix every time the player moves but it doesn't seem to want to. here is the code.
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
int World_Width = 10;
int World_Height = 10;
int Player_X = 1;
int Player_Y = 2;
int Enemy_X = 8;
int Enemy_Y = 1;
int X = Player_X;
int Y = Player_Y;
int Player_Health = 10;
int Enemy_Health = 5;
int Player_Damage = 1;
int Enemy_Damage = 1;
bool PlayerIsAlive = true;
bool EnemyIsAlive = true;
int World[World_Width][World_Height] =
{
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 4, 1},
{1, 2, 0, 0, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 1, 1, 0, 1, 0, 0, 1},
{1, 0, 0, 1, 1, 0, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 0, 1},
{1, 1, 1, 1, 0, 0, 1, 0, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};
int NodeMap[World_Width][World_Height] =
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
};
int NeighborMap[World_Width][World_Height] =
{
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
};
int NodeNumber = 1;
for (int h = 0; h < World_Height; h++)
{
for (int d = 0; d < World_Width; d++)
{
NodeMap[h][d] = NodeNumber;
NodeNumber ++;
}
}
vector<int> queue {};
vector<int> visited {};
string input;
bool AddNode = true;
int QueueNumber = 0;
int Max_iterations = 1000;
int TurnCount = 0;
bool run = true;
while (run)
{
TurnCount += 1;
//Prints out the map
for (int h = 0; h < World_Height; h++)
{
for (int d = 0; d < World_Width; d++)
{
cout << World[h][d] << " ";
}
cout << "\n";
}
cout << "\n";
cout << "Player health: " << Player_Health << "\n";
cout << "Enemy health: " << Enemy_Health << "\n" << "\n";
cout << "What do you want to do; move, attack, or open a chest: ";
//Player movement
cin >> input;
if (input == "w" && World[Player_Y - 1][Player_X] == 0)
{
World[Player_Y ][Player_X] = 0;
Player_Y--;
World[Player_Y][Player_X] = 2;
}
if (input == "a" && World[Player_Y][Player_X - 1] == 0)
{
World[Player_Y][Player_X] = 0;
Player_X--;
World[Player_Y][Player_X] = 2;
}
if (input == "s" && World[Player_Y + 1][Player_X] == 0)
{
World[Player_Y][Player_X] = 0;
Player_Y++;
World[Player_Y][Player_X] = 2;
}
if (input == "d" && World[Player_Y][Player_X + 1] == 0)
{
World[Player_Y][Player_X] = 0;
Player_X++;
World[Player_Y][Player_X] = 2;
}
if (input == "e")
{
if (Player_X == Enemy_X && Player_Y - 1 == Enemy_Y)
{
Enemy_Health -= Player_Damage;
}
if (Player_X == Enemy_X - 1 && Player_Y == Enemy_Y)
{
Enemy_Health -= Player_Damage;
}
if (Player_X == Enemy_X && Player_Y + 1 == Enemy_Y)
{
Enemy_Health -= Player_Damage;
}
if (Player_X == Enemy_X + 1 && Player_Y == Enemy_Y)
{
Enemy_Health -= Player_Damage;
}
}
if ( input == "stop")
{
Player_Health = 0;
}
queue.clear();
QueueNumber = 0;
X = Player_X;
Y = Player_Y;
NeighborMap[Y][X] = 0;
//BFS - Breadth First Search: Pathfinding Algorithim
for (int iterations = 0; iterations < Max_iterations; iterations++)
{
if (World[Y - 1][X] == 0 || World[Y - 1][X] == 4)
{
AddNode = true;
for (int i = 0; i < visited.size(); i++)
{
if (visited[i] == NodeMap[Y - 1][X])
{
AddNode = false;
}
}
if (AddNode)
{
queue.push_back(NodeMap[Y - 1][X]);
NeighborMap[Y - 1][X] = NodeMap[Y][X];
}
}
if (World[Y][X - 1] == 0 || World[Y][X - 1] == 4)
{
AddNode = true;
for (int i = 0; i < visited.size(); i++)
{
if (visited[i] == NodeMap[Y][X - 1])
{
AddNode = false;
}
}
if (AddNode)
{
queue.push_back(NodeMap[Y][X - 1]);
NeighborMap[Y][X - 1] = NodeMap[Y][X];
}
}
if (World[Y + 1][X] == 0 || World[Y + 1][X] == 4)
{
AddNode = true;
for (int i = 0; i < visited.size(); i++)
{
if (visited[i] == NodeMap[Y + 1][X])
{
AddNode = false;
}
}
if (AddNode)
{
queue.push_back(NodeMap[Y + 1][X]);
NeighborMap[Y + 1][X] = NodeMap[Y][X];
}
}
if (World[Y][X + 1] == 0 || World[Y][X + 1] == 4)
{
AddNode = true;
for (int i = 0; i < visited.size(); i++)
{
if (visited[i] == NodeMap[Y][X + 1])
{
AddNode = false;
}
}
if (AddNode)
{
queue.push_back(NodeMap[Y][X + 1]);
NeighborMap[Y][X + 1] = NodeMap[Y][X];
}
}
for (int h = 0; h < World_Height; h++)
{
for (int d = 0; d < World_Width; d++)
{
if(NodeMap[h][d] == queue[QueueNumber])
{
X = d;
Y = h;
}
}
}
visited.push_back(queue[QueueNumber]);
QueueNumber++;
}
//Enemy AI
if (Enemy_Health == 0)
{
if (EnemyIsAlive)
{
World[Enemy_Y][Enemy_X] = 0;
}
EnemyIsAlive = false;
}
if (Player_Health == 0)
{
run = false;
}
}
system("clear");
for (int h = 0; h < World_Height; h++)
{
for (int d = 0; d < World_Width; d++)
{
cout << NeighborMap[h][d] << " ";
}
cout << "\n";
}
cout << "\n";
for (int h = 0; h < World_Height; h++)
{
for (int d = 0; d < World_Width; d++)
{
cout << NodeMap[h][d] << " ";
}
cout << "\n";
}
cout << "GAME OVER" << "\n" << "Thanks for Playing!";
}

MSVC compiler with /arch:AVX2 /fp:fast breaks C++ matrix inversion algorithm

I have matrix inversion algorithm and a 19x19 matrix for testing. Running it in Windows Subsystem for Linux with g++ produces the correct inverted matrix.
In Visual Studio 2017 on Windows it used to work as well. However after I upgraded to Visual Studio 2019, I get a matrix containing all zeros as result. Is MSVC broken or what else is wrong here?
So far I have tested replacing ==0.0/!=0.0 (that in some cases can be unsafe due to round-off) with greater/smaller than a tolerance value, but this does not work either.
The expected result (that I get with g++) is {5.26315784E-2,-1.25313282E-2, ... -1.25000000E-1}.
I compile with Visual Studio 2019 v142, Windows SDK 10.0.19041.0, Release x64, and I get {0,0,...0}. With Debug x64 I get a different (also wrong) result: all matrix entries are -1.99839720E18.
I use C++17 language standard, /O2 /Oi /Ot /Qpar /arch:AVX2 /fp:fast /fp:except-.
I have an i7-8700K that supports AVX2.
I also marked the place where it wrongly returns in Windows in the code. Any help is greatly appreciated.
EDIT: I just found out that the cause of the wrong behavior is /arch:AVX2 in combination with /fp:fast. But I don't understand why. /arch:SSE, /arch:SSE2 and /arch:AVX with /fp:fast work correctly, but not /arch:AVX2. How can different round-off or operation order here trigger entirely different behavior?
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef unsigned int uint;
void println(const string& s="") {
cout << s << endl;
}
struct floatNxN {
uint N{}; // matrix size is NxN
vector<float> M; // matrix data
floatNxN(const uint N, const float* M) : N {N}, M(N*N) {
for(uint i=0; i<N*N; i++) this->M[i] = M[i];
}
floatNxN(const uint N, const float x=0.0f) : N {N}, M(N*N, x) { // create matrix filled with zeros
}
floatNxN() = default;
~floatNxN() = default;
floatNxN invert() const { // returns inverse matrix
vector<double> A(2*N*N); // calculating intermediate values as double is strictly necessary
for(uint i=0; i<N; i++) {
for(uint j=0; j< N; j++) A[2*N*i+j] = (double)M[N*i+j];
for(uint j=N; j<2*N; j++) A[2*N*i+j] = (double)(i+N==j);
}
for(uint k=0; k<N-1; k++) { // at iteration k==2, the content of A is already different in MSVC and g++
if(A[2*N*k+k]==0.0) {
for(uint i=k+1; i<N; i++) {
if(A[2*N*i+k]!=0.0) {
for(uint j=0; j<2*N; j++) {
const double t = A[2*N*k+j];
A[2*N*k+j] = A[2*N*i+j];
A[2*N*i+j] = t;
}
break;
} else if(i+1==N) {
return floatNxN(N);
}
}
}
for(uint i=k+1; i<N; i++) {
const double t = A[2*N*i+k]/A[2*N*k+k];
for(uint j=k; j<2*N; j++) A[2*N*i+j] -= A[2*N*k+j]*t;
}
}
double det = 1.0;
for(uint k=0; k<N; k++) det *= A[2*N*k+k];
if(det==0.0) {
return floatNxN(N);
}
for(int k=N-1; k>0; k--) {
for(int i=k-1; i>=0; i--) {
const double t = A[2*N*i+k]/A[2*N*k+k];
for(uint j=k; j<2*N; j++) A[2*N*i+j] -= A[2*N*k+j]*t;
}
}
floatNxN r = floatNxN(N);
for(uint i=0; i<N; i++) {
const double t = A[2*N*i+i];
for(uint j=0; j<N; j++) r.M[N*i+j] = (float)(A[2*N*i+N+j]/t);
}
return r;
}
string stringify() const { // converts matrix into string without spaces or newlines
string s = "{"+to_string(M[0]);
for(uint i=1; i<N*N; i++) s += ","+to_string(M[i]);
return s+"}";
}
};
int main() {
const float Md[19*19] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-30,-11,-11,-11,-11,-11,-11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
12, -4, -4, -4, -4, -4, -4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, -1, 0, 0, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0,
0, -4, 4, 0, 0, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0,
0, 0, 0, 1, -1, 0, 0, 1,-1, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,
0, 0, 0, -4, 4, 0, 0, 1,-1, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,
0, 0, 0, 0, 0, 1, -1, 0, 0, 1,-1, 1,-1, 0, 0,-1, 1,-1, 1,
0, 0, 0, 0, 0, -4, 4, 0, 0, 1,-1, 1,-1, 0, 0,-1, 1,-1, 1,
0, 2, 2, -1, -1, -1, -1, 1, 1, 1, 1,-2,-2, 1, 1, 1, 1,-2,-2,
0, -4, -4, 2, 2, 2, 2, 1, 1, 1, 1,-2,-2, 1, 1, 1, 1,-2,-2,
0, 0, 0, 1, 1, -1, -1, 1, 1,-1,-1, 0, 0, 1, 1,-1,-1, 0, 0,
0, 0, 0, -2, -2, 2, 2, 1, 1,-1,-1, 0, 0, 1, 1,-1,-1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,-1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1,-1, 1, 0, 0,-1, 1, 1,-1
};
floatNxN M(19, Md);
floatNxN Mm1 = M.invert();
println(Mm1.stringify());
}
It seems that it is the comparison against literal 0 that breaks the algorithm with the optimizations on. Particularly the 1st one kills it, because the result would need to be exactly 0 for the correct action.
Generally instead of comparing a floating point value against literal zero, it is better to compare the absolute value against a very small constant.
This seems to work:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
typedef unsigned int uint;
void println(const string& s = "") {
cout << s << endl;
}
struct floatNxN {
const double epsilon = 1E-12;
uint N{}; // matrix size is NxN
vector<float> M; // matrix data
floatNxN(const uint N, const float* M) : N{ N }, M(N* N) {
for (uint i = 0; i < N * N; i++) this->M[i] = M[i];
}
floatNxN(const uint N, const float x = 0.0f) : N{ N }, M(N* N, x) { // create matrix filled with zeros
}
floatNxN() = default;
~floatNxN() = default;
floatNxN invert() const { // returns inverse matrix
vector<double> A(2 * N * N); // calculating intermediate values as double is strictly necessary
for (uint i = 0; i < N; i++) {
for (uint j = 0; j < N; j++) A[2 * N * i + j] = (double)M[N * i + j];
for (uint j = N; j < 2 * N; j++) A[2 * N * i + j] = (double)(i + N == j);
}
for (uint k = 0; k < N - 1; k++) { // at iteration k==2, the content of A is already different in MSVC and g++
if (fabs(A[2 * N * k + k]) < epsilon) { // comparing with 0 was the killer here
for (uint i = k + 1; i < N; i++) {
if (fabs(A[2 * N * i + k]) > epsilon) {
for (uint j = 0; j < 2 * N; j++) {
const double t = A[2 * N * k + j];
A[2 * N * k + j] = A[2 * N * i + j];
A[2 * N * i + j] = t;
}
break;
} else if (i + 1 == N) {
return floatNxN(N);
}
}
}
for (uint i = k + 1; i < N; i++) {
const double t = A[2 * N * i + k] / A[2 * N * k + k];
for (uint j = k; j < 2 * N; j++) A[2 * N * i + j] -= A[2 * N * k + j] * t;
}
}
double det = 1.0;
for (uint k = 0; k < N; k++) det *= A[2 * N * k + k];
if (fabs(det) < epsilon) {
return floatNxN(N);
}
for (int k = N - 1; k > 0; k--) {
for (int i = k - 1; i >= 0; i--) {
const double t = A[2 * N * i + k] / A[2 * N * k + k];
for (uint j = k; j < 2 * N; j++) A[2 * N * i + j] -= A[2 * N * k + j] * t;
}
}
floatNxN r = floatNxN(N);
for (uint i = 0; i < N; i++) {
const double t = A[2 * N * i + i];
for (uint j = 0; j < N; j++) r.M[N * i + j] = (float)(A[2 * N * i + N + j] / t);
}
return r;
}
string stringify() const { // converts matrix into string without spaces or newlines
string s = "{" + to_string(M[0]);
for (uint i = 1; i < N * N; i++) s += "," + to_string(M[i]);
return s + "}";
}
};
int main() {
const float Md[19 * 19] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-30,-11,-11,-11,-11,-11,-11, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
12, -4, -4, -4, -4, -4, -4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, -1, 0, 0, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0,
0, -4, 4, 0, 0, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0,
0, 0, 0, 1, -1, 0, 0, 1,-1, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,
0, 0, 0, -4, 4, 0, 0, 1,-1, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,
0, 0, 0, 0, 0, 1, -1, 0, 0, 1,-1, 1,-1, 0, 0,-1, 1,-1, 1,
0, 0, 0, 0, 0, -4, 4, 0, 0, 1,-1, 1,-1, 0, 0,-1, 1,-1, 1,
0, 2, 2, -1, -1, -1, -1, 1, 1, 1, 1,-2,-2, 1, 1, 1, 1,-2,-2,
0, -4, -4, 2, 2, 2, 2, 1, 1, 1, 1,-2,-2, 1, 1, 1, 1,-2,-2,
0, 0, 0, 1, 1, -1, -1, 1, 1,-1,-1, 0, 0, 1, 1,-1,-1, 0, 0,
0, 0, 0, -2, -2, 2, 2, 1, 1,-1,-1, 0, 0, 1, 1,-1,-1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,-1,-1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1,-1,-1, 1, 0, 0, 1,-1,-1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 1,-1, 0, 0, 1,-1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1,-1, 1, 0, 0,-1, 1, 1,-1
};
floatNxN M(19, Md);
floatNxN Mm1 = M.invert();
println(Mm1.stringify());
}

GSL complex matrix - eigenvalues/eigenvectors

I've written a program which is computing the eigenvalues and eigenvectors of a hermitian matrix.
Does anyone know how this is done in GSL properly? Here is what I already have.
//hermitian matrix
0 1 0 -i
1 0 -i 0
0 i 0 1
i 0 1 0
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_complex_math.h>
#include <gsl/gsl_eigen.h>
using namespace std;
const int N = 4;
int main(){
gsl_eigen_hermv_workspace *workN = gsl_eigen_hermv_alloc(N);
gsl_matrix_complex *A = gsl_matrix_complex_alloc(N, N);
gsl_complex i = gsl_complex_rect(0.0,1.0);
gsl_complex ii = gsl_complex_rect(0.0,-1.0);
gsl_vector *eval = gsl_vector_alloc(N);
gsl_matrix_complex *evec = gsl_matrix_complex_alloc(N, N);
double mTab[] = {
0, 1, 0, 5,
1, 0, 5, 0,
0, 5, 0, 1,
5, 0, 1, 0
};
gsl_matrix_complex_view tmpM = gsl_matrix_complex_view_array(mTab, N, N);
gsl_matrix_complex_memcpy(A, &tmpM.matrix);
gsl_matrix_complex_set(A, 0, 3, ii);
gsl_matrix_complex_set(A, 1, 2, ii);
gsl_matrix_complex_set(A, 2, 1, i);
gsl_matrix_complex_set(A, 3, 0, i);
gsl_eigen_hermv(A, eval, evec, workN);
for(int i=0; i < N; i++){
for(int j=0; j < N; j++){
gsl_complex z = gsl_matrix_complex_get(A, i, j);
cout << GSL_REAL(z) << "+ i" << GSL_IMAG(z) << " ";
}
cout << "\n";
}
cout << "\n";
for(int i=0; i < N; i++){
cout << gsl_vector_get(eval, i) << " ";
}
return 0;
}
This is how I output the eigenvectors
for(int i=0; i < N; i++){
for(int j=0; j < N; j++){
gsl_complex z = gsl_matrix_complex_get(A, i, j);
cout << GSL_REAL(z) << "+ i" << GSL_IMAG(z) << " ";
}
cout << "\n";
}
Finally, here's the way I declared the matrix in question.
double mTab[] = {
0, 1, 0, 5,
1, 0, 5, 0,
0, 5, 0, 1,
5, 0, 1, 0
};
Later, I added the complex numbers.
I managed to print the eigenvectors but I don't know how to do that for the eigenvalues. Any help with that is appreciated?.
You have an error in using the double mTab for gsl_matrix_complex_view_array. This assumes an array of complex numbers represented as real parts followed by imaginary parts in one large array of double values. You can change your definition to:
double mTab[] = {
0, 0, 1, 0, 0, 0, 5, 0,
1, 0, 0, 0, 5, 0, 0, 0,
0, 0, 5, 0, 0, 0, 1, 0,
5, 0, 0, 0, 1, 0, 0, 0,
};
(Which also means you don't need to use a "dummy" variable of 5 just to rewrite it by ±i later.) Then the code for printing eigenvalues works well.
Also you have a typo in the eigenvector printing loop: it should be
gsl_complex z = gsl_matrix_complex_get(evec, i, j);
not
gsl_complex z = gsl_matrix_complex_get(A, i, j);

Transfer a 2D array to a csv file?

I have a matrix called "temp_matrix" that looks kind of like this:
0.0,100.0,100.0,100.0,
0.0,45.1,60.6,66.2,0,
0.0,45.1,60.6,66.2,0,
0.0,100.0,100.0,100.0,0,
...except mine is a 20x20 matrix.
I've tried:
ofstream excel_plate("plate.csv");
excel_plate.write(temp_matrix[0],20);
excel_plate.close();
cout << endl;
but can't compile.
I've tried:
ofstream excel_plate("plate.csv");
excel_plate << temp_matrix[0], 20, 20;
excel_plate.close();
...but just get a csv file with a string of characters in the very first cell that looks like this: 0052EE98.
Here is my code:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <math.h>
#include <Windows.h>
#include <algorithm>
#include <string>
#include <array>
#undef max
using namespace std;
const double neighbors = 4;
// START FUNCTION: Update Elements
void average(double *temp_matrix, int ROWS, int COLUMNS)
{
int i = 0;
int j = 0;
double row_left = 0;
double row_right = 0;
double column_up = 100;
double column_down = 0;
double sum = 0;
double av = 0;
for (int i = 1; i < ROWS - 1; i++)
{
for (int j = 1; j < COLUMNS - 1; j++)
{
/*
cout << "row_left:" << *(temp_matrix + i*ROWS + (j - 1)) << " ";
cout << "row_right:" << *(temp_matrix + i*ROWS + (j + 1)) << " ";
cout << "column_up:" << *(temp_matrix + (i - 1)*ROWS + j) << " ";
cout << "column_down:" << *(temp_matrix + (i + 1)*ROWS + j) << " ";
*/
row_left = *(temp_matrix + i*ROWS + (j-1));
row_right = *(temp_matrix + i*ROWS + (j + 1));
column_up = *(temp_matrix + (i-1)*ROWS + j);
column_down = *(temp_matrix + (i+1)*ROWS + j);
sum = row_left + row_right + column_up + column_down;
av = sum / neighbors;
*(temp_matrix + i*ROWS + j) = av;
}
}
}
// END FUNCTION: Update Elements
// START FUNCTION: Updtate Until Stable
void update(double *temp_matrix, int ROWS, int COLUMNS)
{
int i = 0;
int j = 0;
double row_left = 0;
double row_right = 0;
double column_up = 100;
double column_down = 0;
double sum = 0;
double old_num = 0;
double new_num = 0;
double difference = 0;
double max_change = .11;
while (max_change > .1)
{
max_change = -1;
for (int i = 1; i < ROWS - 1; i++)
{
for (int j = 1; j < COLUMNS - 1; j++)
{
old_num = *(temp_matrix + i*ROWS + j);
/*
cout << "row_left:" << *(temp_matrix + i*ROWS + (j - 1)) << " ";
cout << "row_right:" << *(temp_matrix + i*ROWS + (j + 1)) << " ";
cout << "column_up:" << *(temp_matrix + (i - 1)*ROWS + j) << " ";
cout << "column_down:" << *(temp_matrix + (i + 1)*ROWS + j) << " ";
*/
row_left = *(temp_matrix + i*ROWS + (j - 1));
row_right = *(temp_matrix + i*ROWS + (j + 1));
column_up = *(temp_matrix + (i - 1)*ROWS + j);
column_down = *(temp_matrix + (i + 1)*ROWS + j);
sum = row_left + row_right + column_up + column_down;
new_num = sum / neighbors;
difference = new_num - old_num;
if (difference > max_change)
{
max_change = difference;
}
*(temp_matrix + i*ROWS + j) = new_num;
}
}
}
}
// END FUNCTION: Update Until Stable
// START FUNCTION: Print Array
void print_array(double *temp_matrix, int ROWS, int COLUMNS)
{
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLUMNS; j++)
{
if (j > 0)
{
cout << ",";
}
cout << fixed << setw(5) << setprecision(1) << *(temp_matrix + i*ROWS + j);
}
cout << endl;
}
}
// END FUNCTION: Print Array
// START FUNCTION: Print 4 Excel
void print_excel(double *temp_matrix, int ROWS, int COLUMNS)
{
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLUMNS; j++)
{
cout << fixed << setprecision(1) << *(temp_matrix + i*ROWS + j) << ",";
}
cout << endl;
}
}
// END FUNCTION: Print 4 Excel
int main()
{
const int ROWS = 20;
const int COLUMNS = 20;
double temp_matrix[ROWS][COLUMNS] =
{
{ 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 0 }
};
print_array(temp_matrix[0], 20, 20);
system("pause");
cout << endl << endl;
average(temp_matrix[0], 20, 20);
print_array(temp_matrix[0], 20, 20);
system("pause");
cout << endl << endl;
update(temp_matrix[0], 20, 20);
print_array(temp_matrix[0], 20, 20);
system("pause");
cout << endl << endl;
print_excel(temp_matrix[0], 20, 20);
ofstream excel_plate("plate.csv");
if (excel_plate.is_open())
{
excel_plate << temp_matrix[0], 20, 20;
excel_plate.close();
}
else
{
cout << "Unable to open file.";
}
/*
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLUMNS; j++)
{
if (j > 0)
{
cout << ",";
}
cout << temp_matrix[i][j];
}
cout << endl;
}
*/
system("pause");
return 0;
}
This should be very, very simple. Please kindly help a noob out. :)
P.S. Because this is an assignment, you'll notice that I print out several matrices. The last one I print out is the format in which the matrix needs to be transferred to a .csv file.
The simplest way would be something like the following (assuming you can use c++11)
std::ofstream out("test.csv");
for (auto& row : temp_matrix) {
for (auto col : row)
out << col <<',';
out << '\n';
}
So, this code conatains a functions that should be able to transfer any 2d string array into a csv file
#include <iostream>
#include <fstream>
#include<string>
/* This is for a string array, but if you want to use any other type, just replace
'std::string' with int,double....*/
template <size_t row, size_t col>
void twodarray2csv(std::string(&array)[row][col], std::string filename)
{
std::ofstream myfile;
myfile.open(filename);
for (size_t i = 0; i < row; ++i)
{
for (size_t j = 0; j < col; ++j)
if (j < (col - 1)) {
myfile << array[i][j] << ",";
}
else if (j == (col - 1)) {
myfile << array[i][j] << "\n";
}
}
}
Th template gets the row size and column size and also opens ofstream which is basically for just opening the csv file that will be the output file
int main() {
//example
std::string ArrayName[9][3];
/* this for loop is just there to populate the array, if you have an array
already skip this step */
#include <iostream>
#include <fstream>
#include<string>
/* This is for a string array, but if you want to use any other type, just replace
'std::string' with int,double....*/
template <size_t row, size_t col>
void twodarray2csv(std::string(&array)[row][col], std::string filename)
{
std::ofstream myfile;
myfile.open(filename);
for (size_t i = 0; i < row; ++i)
{
for (size_t j = 0; j < col; ++j)
if (j < (col - 1)) {
myfile << array[i][j] << ",";
}
else if (j == (col - 1)) {
myfile << array[i][j] << "\n";
}
}
}
So the function above uses a template to get the row size and column size of the array, after which it iterates through the array so that when it passes by elements of the same row it adds a comma to the file and at the end of each row it adds a new line (\n) which is a row separator
The part below is an example of how to use it and how it works
First i just created a an Array called ArrayName, and populated it with just some numbers (int number)
int number = 0;
for (int i = 0; i < 9; i++) {
for (int x = 0; x < 3; x++) {
ArrayName[i][x] = number;
number++;
}
}
//this part converts the array to a csv file of desried name
twodarray2csv(ArrayName, "outputfile.csv");
return 0;
}
The output will be a csv file with the name "outputfile.csv" stored in the same folder with the cpp file you have

Why is my program having an instance where "Vector Subscript out of Range"?

Bassicly my code is supposed to be taking ints from int tt[] in main()
const int tt[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
The program then is exposed to give cordinates for a vector based on its sequential order and give cordinates for the texture if its gives #1. Based on my cout statement tiletype = tt[count]; I can tell the program crashes after reading the fith zero from int tt[] and gives the error Vector Subscript out of Range.
I assume the problem fall under this section of my code:
for(x = 1; x < c;++x)
{
for(y = 0; y < r;++y)
{
tiletype = tt[count];
cout <<tiletype<<", ";
vertices[a].position = sf::Vector2f((0+y)*ts,ts*(x+1)+80);
vertices[b].position = sf::Vector2f((0+y)*ts, (0+x)*ts+80);
vertices[d].position = sf::Vector2f(ts+(y*ts),(0+x)*ts+80);
vertices[e].position = sf::Vector2f(ts+(y*ts), ts*(x+1)+80);
vertices[a].texCoords = mapcords(tiletype,0);
vertices[b].texCoords = mapcords(tiletype,1);
vertices[d].texCoords = mapcords(tiletype,2);
vertices[e].texCoords = mapcords(tiletype,3);
a += 4; b += 4; d += 4; e += 4;count++;
}
row += 1;
cout <<endl<<"Row "<<row<<": "; y = 0;
}
This is the rest of the code.
#include <SFML/Graphics.hpp>
#include <iostream>
using namespace std;
using namespace sf;
Vector2f mapcords(int tt,int corner);
Vector2f mapcords(int tt,int corner)
{
if(tt ==0)
{
if (corner ==1)
{return Vector2f(48,8 );}
if(corner == 1)
{return Vector2f(48,0);}
if (corner ==2)
{return Vector2f(56, 0);}
if (corner == 3)
{return sf::Vector2f(56, 8);}
}
else{
if(corner ==0)
{return Vector2f(0,8 );}
if(corner == 1)
{return Vector2f(0,0);}
if (corner ==2)
{return Vector2f(8, 0);}
if (corner == 3)
{return sf::Vector2f(8, 8);}
}
return Vector2f(0,0 );
}
class drawmap : public sf::Drawable, public sf::Transformable
{
public:
bool load(const string& tileset,const int* tt, int ts, int r, int c, int num)
{
count =0; row =1; a = 0; b = 1; d = 2; e = 3;y=0;x=0;
tiletex.setRepeated(true);
if (!tiletex.loadFromFile(tileset))
return false;
tiletex.setRepeated(true);
vertices.setPrimitiveType(sf::Quads);
vertices.resize(2 * 2 * 4);
cout <<endl<<"Row "<<row<<": ";
for(x = 1; x < c;++x)
{
for(y = 0; y < r;++y)
{
tiletype = tt[count];
cout <<tiletype<<", ";
vertices[a].position = sf::Vector2f((0+y)*ts,ts*(x+1)+80);
vertices[b].position = sf::Vector2f((0+y)*ts, (0+x)*ts+80);
vertices[d].position = sf::Vector2f(ts+(y*ts),(0+x)*ts+80);
vertices[e].position = sf::Vector2f(ts+(y*ts), ts*(x+1)+80);
vertices[a].texCoords = mapcords(tiletype,0);
vertices[b].texCoords = mapcords(tiletype,1);
vertices[d].texCoords = mapcords(tiletype,2);
vertices[e].texCoords = mapcords(tiletype,3);
a += 4; b += 4; d += 4; e += 4;count++;
}
row += 1;
cout <<endl<<"Row "<<row<<": "; y = 0;
}
return true;
}
private:
int row;
int count;
int y,x;
int a,b,d,e;
int tiletype;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
states.texture = &tiletex;
target.draw(vertices, states);
}
sf::VertexArray vertices;
sf::Texture tiletex;
};
Even if r and c are properly initialized to (I assume) 4, once you've looped to the point where y = 4 (ie. x is incrementing) you don't reset a, b, d or e - meaning on the fifth loop through, you have a = 16, b = 17, d = 19 and e = 20, but then you still try to access vertices[a] (and b and d and e). Since vertices just before this was resized to (2 * 2 * 4), or 16, you then access the vector out of its bounds. Hence, the vector subscript out of range error.
In order to hold enough vertices for 4 * the number of tiles you want to put in the vector, you're going to need to do something like:
vertices.resize(4 * r * c);