while loop is changing every object and not iterating through - c++

#include <stdio.h>
#include <iostream>
#include "Vector.h"
#include <string.h>
#include <math.h>
#include "Matrix.h"
#include <list>
using namespace std;
// format for a Matrix
char* Matrix::printM(){
char* s = new char[5000*1024];
int i;
for(i=0;i < this->dimension.rows;i++){
int j;
for(j=0;j< this->dimension.columns;j++){
Vector* tmp = this->columns[j];
int x = this->dimension.columns - 1;
if(j == 0){
char buffer[500];
//it0oa(v->coordinate[i],buffer,sizeof(int));
snprintf(buffer,5000,"%f",tmp->coordinate[i]);
strncat(s,"|", 1+ strlen(s));
strncat(s,buffer, strlen(s) + strlen(buffer));
strncat(s,",",strlen(s) + 1);
}else if(j == x){
char buffer[500];
snprintf(buffer,5000,"%f",tmp->coordinate[i]);
strncat(s,buffer,strlen(s) + strlen(buffer));
strncat(s,"|\n",strlen(s)+2);
}else{
char buffer[500];
snprintf(buffer,5000,"%f",tmp->coordinate[i]);
strncat(s,buffer,strlen(s) + strlen(buffer));
strncat(s,",",strlen(s) + 1);
}
}
}
return s;
}
Matrix::Matrix(int di,int de){
this->dimension.rows =de;
this->dimension.columns =di;
this->columns.assign(di,new Vector(de));
}
Matrix::Matrix(std::vector<Vector*> v, int di){
this->dimension.columns = v.size();
this->columns = v;
int it;
this->dimension.rows = v[0]->dimension;
}
Matrix& Matrix::operator+(const Matrix& v){
Matrix* mt = new Matrix(this->dimension.columns,6);
mt->dimension = this->dimension;
int i;
for(i=0;i< mt->dimension.columns;i++){
//mt->columns.push_back(&(*this->columns[i] + *v.columns[i]));
mt->columns[i] = &(*this->columns[i] + *v.columns[i]);
printf("%s\n",mt->columns[0]->printV());
}
return *mt;
}
Matrix& Matrix::operator-(const Matrix& v){
Matrix* mt = new Matrix(this->dimension.columns,7);
mt->dimension = this->dimension;
int i;
for(i=0;i< mt->dimension.columns;i++){
//mt->columns.push_back(&(*this->columns[i] + *v.columns[i]));
mt->columns[i] = &(*this->columns[i] - *v.columns[i]);
printf("%s\n",mt->columns[0]->printV());
}
return *mt;
}
Matrix& Matrix::operator*(const double& v){
Matrix* mt = new Matrix(this->dimension.columns,7);
mt->dimension = this->dimension;
int i;
for(i=0;i< mt->dimension.columns;i++){
//mt->columns.push_back(&(*this->columns[i] + *v.columns[i]));
mt->columns[i] = &(*this->columns[i] * v);
//printf("%s\n",mt->columns[0]->printV());
}
return *mt;
}
std::vector<Vector*> Matrix::row_equiv(Matrix* m){
std::list<Vector*> result;
int i;
for(i=0;i< m->dimension.rows;i++){
std::list<double> lists;
lists.push_back(m->dimension.columns);
int j;
for(j=0;j< m->dimension.columns;j++){
Vector* tmp = m->columns[j];
lists.push_back(tmp->coordinate[i]);
}
j=0;
//std::initializer_list<double> list_h = lists;
Vector* tmp = new Vector(lists);
result.push_back(tmp);
}
std::vector<Vector*> x{std::begin(result),std::end(result)};
return x;
}
Matrix* Matrix::transpose(){
std::vector<Vector*> b = row_equiv(this);
Matrix* mt = new Matrix(b,this->dimension.rows);
return mt;
}
Matrix* Matrix::upperTriangular(){
std::vector<Vector*> tmp = row_equiv(this);
if(this->is_square()){
int j;
for(j=0;j<this->dimension.columns;j++){
double pivot = tmp[j]->coordinate[j];
int i;
for(i=j+1;i<this->dimension.rows;i++){
tmp[i] = &((*tmp[i]) - (*tmp[j] * (tmp[i]->coordinate[j]/pivot)));
}
}
}else if(this->dimension.rows > this->dimension.columns){
//printf("Hello world,\n");
int j;
for(j=0;j<this->dimension.columns;j++){
double pivot = tmp[j]->coordinate[j];
printf("%f\n",pivot);
int i;
for(i=j+1;i< this->dimension.rows;i++){
tmp[i] = &((*tmp[i]) + (*tmp[j] * (tmp[i]->coordinate[j]/-1*pivot)));
printf(" The vector is %s\n",tmp[i]->printV());
}
}
}else if(this->dimension.rows < this->dimension.columns){
printf("Not Hello World!");
}
Matrix* result = new Matrix(tmp,this->dimension.rows);
return result->transpose();
}
// This is supposed to give me the multiplication of matrices but it's not working right now.
Matrix& Matrix::operator*(const Matrix& v){
if(this->dimension.columns == v.dimension.rows){
Matrix* mt = new Matrix(v.dimension.columns,this->dimension.rows);
mt->dimension.rows = this->dimension.rows;
std::vector<Vector*> tmp = row_equiv(this);
std::vector<Vector* > result(v.dimension.columns, new Vector(this->dimension.rows));
for(auto i =0; i < tmp.size();i++){ //for each rows of the first matrix
int j =0;
while(j< this->dimension.columns){ //for each columns of the second matrix
//printf("%f and %f\n",tmp[i]->dimension,this->columns[j]->dimension);
//double x = *tmp[i] * *v.columns[j];
//printf("%f\n",x);
//mt->columns[j]->coordinate[i] = (*tmp[i] * *v.columns[j]); // This line is giving me problems.
//printf("THis is after the code\n");
result[j]->coordinate[i] = (*tmp[i] * *v.columns[j]);
printf("%s and %s %f and %s %s an j = %d\n",tmp[i]->printV(),v.columns[j]->printV(),result[j]->coordinate[i],result[j]->printV(),result[0]->printV(),j);
j++;
}
printf("%s\n",result[0]->printV());
}
return *mt;
}
Matrix* mt = new Matrix(3,2);
return *mt;
}
The problem is with this piece of code
Matrix& Matrix::operator*(const Matrix& v){
if(this->dimension.columns == v.dimension.rows){
Matrix* mt = new Matrix(v.dimension.columns,this->dimension.rows);
mt->dimension.rows = this->dimension.rows;
std::vector<Vector*> tmp = row_equiv(this);
std::vector<Vector* > result(v.dimension.columns, new Vector(this->dimension.rows));
for(auto i =0; i < tmp.size();i++){ //for each rows of the first matrix
int j =0;
while(j< this->dimension.columns){ //for each columns of the second matrix
//printf("%f and %f\n",tmp[i]->dimension,this->columns[j]->dimension);
//double x = *tmp[i] * *v.columns[j];
//printf("%f\n",x);
//mt->columns[j]->coordinate[i] = (*tmp[i] * *v.columns[j]); // This line is giving me problems.
//printf("THis is after the code\n");
result[j]->coordinate[i] = (*tmp[i] * *v.columns[j]);
printf("%s and %s %f and %s %s an j = %d\n",tmp[i]->printV(),v.columns[j]->printV(),result[j]->coordinate[i],result[j]->printV(),result[0]->printV(),j);
j++;
}
printf("%s\n",result[0]->printV());
}
return *mt;
}
Matrix* mt = new Matrix(3,2);
return *mt;
}
The function is supposed to multiply 2 matrices together.
This line is changing result[0] every time it runs and I don't know why. result is a vector of Vector* and the while loop is supposed to iterate through the Vector of the vector(list) and changing the ith component but every time the loop goes through it changes the previous Vector.
result[j]->coordinate[i] = (*tmp[i] * *v.columns[j])
This is the implementation :
for(auto i=0; i < this->dimension.rows;i++){
for(auto j=0; j<v.dimension.columns;j++){
for(auto k=0; k< this->dimension.rows;k++){
result[j]->coordinate[i] += this->columns[i]->coordinate[k] * v.columns[k]->coordinate[j];
printf("j = %d, %s and %s\n",j,result[j]->printV(), result[0]->printV());
}
}
}
When j = 1, result[0] also changes and i don't know why. This is the ouput .
j = 0, <2.000000,0.000000> and <2.000000,0.000000>
j = 0, <2.000000,0.000000> and <2.000000,0.000000>
j = 1, <2.000000,0.000000> and <2.000000,0.000000>
j = 1, <1.000000,0.000000> and <1.000000,0.000000>
j = 2, <1.000000,0.000000> and <1.000000,0.000000>
j = 2, <1.000000,0.000000> and <1.000000,0.000000>
j = 0, <1.000000,-1.000000> and <1.000000,-1.000000>
j = 0, <1.000000,-1.000000> and <1.000000,-1.000000>
j = 1, <1.000000,-1.000000> and <1.000000,-1.000000>
j = 1, <1.000000,1.000000> and <1.000000,1.000000>
j = 2, <1.000000,1.000000> and <1.000000,1.000000>
j = 2, <1.000000,1.000000> and <1.000000,1.000000>

Matrix multiplication is defined differently. It requires 3 nested for loops - not just two:
For every pair (i,j), you need to iterate over all values of k, and do the following pseudocode:
result = zeros(a.rows,b.cols)
for i = 0:a.rows-1
for j = 0:b.cols-1
for k = 0:a.cols-1
result(i,j) += a(i,k) * b(k,j)

Related

Why AddressSanitizer:DEADLYSIGNAL?

class Solution {
int maxRow, maxCol;
int x[4] = {1, -1, 0, 0};
int y[4] = {0, 0, 1, -1};
bool isValid(int row, int col){
return (row >= 0 && row < maxRow && col >= 0 && col < maxCol);
}
int longestPath(int row, int col, vector<vector<int>>& matrix, vector<vector<int>>& dp){
if(dp[row][col] != -1){
return dp[row][col];
}
int longestCurrPath = 1;
for(int dir = 0; dir < 4; ++dir){
int newRow = row + x[dir];
int newCol = col + y[dir];
if(isValid(newRow, newCol) && matrix[col][row] > matrix[newRow][newCol]){
longestCurrPath = max(longestCurrPath, longestPath(newRow, newCol, matrix, dp) + 1);
}
}
return dp[row][col] = longestCurrPath;
}
public:
int longestIncreasingPath(vector<vector<int>>& matrix) {
maxRow = matrix.size();
maxCol = matrix[0].size();
int LIP = 1;
vector<vector<int>> dp(maxRow + 1, vector<int>(maxCol + 1, -1));
for(int row = 0; row < maxRow; ++row){
for(int col = 0; col < maxCol; ++col){
if(dp[row][col] == -1)
LIP = max(LIP, longestPath(row, col, matrix, dp));
}
}
return LIP;
}
};
AddressSanitizer:DEADLYSIGNAL
==31==ERROR: AddressSanitizer: stack-overflow on address 0x7ffe60cafff8 (pc 0x0000003466d2 bp 0x7ffe60cb0070 sp 0x7ffe60cb0000 T0)
==31==ABORTING
Answer: Stackoverflow.
Your recursive logic is buggy. And you perpetually end up in a situation like this:
See comments in the code below
int longestPath(int row, int col, vector<vector<int>>& matrix, vector<vector<int>>& dp){
if(dp[row][col] != -1){
// Termination depends on `dp`
return dp[row][col];
}
int longestCurrPath = 1;
for(int dir = 0; dir < 4; ++dir){
int newRow = row + x[dir];
int newCol = col + y[dir];
if(isValid(newRow, newCol) && matrix[col][row] > matrix[newRow][newCol]) {
// Making recursive calls without ever influencing `dp`
longestCurrPath = max(longestCurrPath, longestPath(newRow, newCol, matrix, dp) + 1);
}
}
// This is the only time you change `dp`
return dp[row][col] = longestCurrPath;
}

How to improve memory management for matrix multiplication

I'm trying to learn about matrix multiplication and encounter this code for Strassen multiplication vs standard matrix multiplication, so I've tried to implement it. However, this code uses too much memory to the point that when the matrix it's big enough it kills the program. Also, because it uses too much memory it takes longer to process.
I'm not too comfortable to mess around with the code too much since I don't fully understand complex memory management and I would really like to learn about this topic.
Build in the code there's a cut parameter and found that at 320 makes it run faster and seems like improves with memory management.
EDIT. I've implemented a copy constructor, destructor and a function to track memory usage and it fixed the memory leaks it was having, but the big jump on the time between 1990 dimension to 2100 still there for the Strassen matrix.
matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <vector>
using namespace std;
class matrix
{
public:
matrix(int dim, bool random, bool strassen);
matrix(const matrix& old_m);
inline int dim() {
return dim_;
}
inline int& operator()(unsigned row, unsigned col) {
return data_[dim_ * row + col];
}
inline int operator()(unsigned row, unsigned col) const {
return data_[dim_ * row + col];
}
void print();
matrix operator+(matrix b);
matrix operator-(matrix b);
~matrix();
private:
int dim_;
int* data_;
};
#endif
Matrix.cpp
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
#include "SAMmatrix.h"
using namespace std;
matrix::matrix(int dim, bool random, bool strassen) : dim_(dim) {
if (strassen) {
int dim2 = 2;
while (dim2 < dim)
dim2 *= 2;
dim_ = dim2;
}
data_ = new int[dim_ * dim_];
if (!random) return;
for (int i = 0; i < dim_ * dim_; i++)
data_[i] = rand() % 10;
}
matrix::matrix(const matrix& old_m){
dim_ = old_m.dim_;
data_ = new int[dim_ * dim_];
for (int i = 0; i < dim_ * dim_; i++)
data_[i] = old_m.data_[i];
}
void matrix::print() {
for (int i = 0; i < dim_; i++) {
for (int j = 0; j < dim_; j++)
cout << (*this)(i, j) << " ";
cout << "\n";
}
cout << "\n";
}
matrix matrix::operator+(matrix b) {
matrix c(dim_, false, false);
for (int i = 0; i < dim_; i++)
for (int j = 0; j < dim_; j++)
c(i, j) = (*this)(i, j) + b(i, j);
return c;
}
matrix matrix::operator-(matrix b) {
matrix c(dim_, false, false);
for (int i = 0; i < dim_; i++)
for (int j = 0; j < dim_; j++)
c(i, j) = (*this)(i, j) - b(i, j);
return c;
}
matrix::~matrix()
{
delete [] data_;
}
Matrix main
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "SAMmatrix.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
typedef pair<matrix, long> result;
int cut = 64;
matrix mult_std(matrix a, matrix b)
{
matrix c(a.dim(), false, false);
for (int i = 0; i < a.dim(); i++)
for (int k = 0; k < a.dim(); k++)
for (int j = 0; j < a.dim(); j++)
c(i, j) += a(i, k) * b(k, j);
return c;
}
matrix get_part(int pi, int pj, matrix m)
{
matrix p(m.dim() / 2, false, true);
pi = pi * p.dim();
pj = pj * p.dim();
for (int i = 0; i < p.dim(); i++)
for (int j = 0; j < p.dim(); j++)
p(i, j) = m(i + pi, j + pj);
return p;
}
void set_part(int pi, int pj, matrix* m, matrix p)
{
pi = pi * p.dim();
pj = pj * p.dim();
for (int i = 0; i < p.dim(); i++)
for (int j = 0; j < p.dim(); j++)
(*m)(i + pi, j + pj) = p(i, j);
}
matrix mult_strassen(matrix a, matrix b)
{
if (a.dim() <= cut)
return mult_std(a, b);
matrix a11 = get_part(0, 0, a);
matrix a12 = get_part(0, 1, a);
matrix a21 = get_part(1, 0, a);
matrix a22 = get_part(1, 1, a);
matrix b11 = get_part(0, 0, b);
matrix b12 = get_part(0, 1, b);
matrix b21 = get_part(1, 0, b);
matrix b22 = get_part(1, 1, b);
matrix m1 = mult_strassen(a11 + a22, b11 + b22);
matrix m2 = mult_strassen(a21 + a22, b11);
matrix m3 = mult_strassen(a11, b12 - b22);
matrix m4 = mult_strassen(a22, b21 - b11);
matrix m5 = mult_strassen(a11 + a12, b22);
matrix m6 = mult_strassen(a21 - a11, b11 + b12);
matrix m7 = mult_strassen(a12 - a22, b21 + b22);
matrix c(a.dim(), false, true);
set_part(0, 0, &c, m1 + m4 - m5 + m7);
set_part(0, 1, &c, m3 + m5);
set_part(1, 0, &c, m2 + m4);
set_part(1, 1, &c, m1 - m2 + m3 + m6);
return c;
}
pair<matrix, long> run(matrix(*f)(matrix, matrix), matrix a, matrix b)
{
struct timeval start, end;
gettimeofday(&start, NULL);
matrix c = f(a, b);
gettimeofday(&end, NULL);
long e = (end.tv_sec * 1000 + end.tv_usec / 1000);
long s = (start.tv_sec * 1000 + start.tv_usec / 1000);
return pair<matrix, long>(c, e - s);
}
int parseLine(char* line){ /* overflow*/
// This assumes that a digit will be found and the line ends in " Kb".
int i = strlen(line);
const char* p = line;
while (*p <'0' || *p > '9') p++;
line[i-3] = '\0';
i = atoi(p);
return i;
}
int getValue(){ //Note: this value is in KB!
FILE* file = fopen("/proc/self/status", "r");
int result = -1;
char line[128];
while (fgets(line, 128, file) != NULL){
if (strncmp(line, "VmSize:", 7) == 0){
result = parseLine(line);
break;
}
}
fclose(file);
return result;
}
int main()
{
/* test cut of for strassen
/*
for (cut = 2; cut <= 512; cut++) {
matrix a(512, true, true);
matrix b(512, true, true);
result r = run(mult_strassen, a, b);
cout << cut << " " << r.second << "\n";
}
*/
/* performance test: standard and strassen */
/*1024 going up by 64*/
for (int dim = 1500; dim <= 2300; dim += 200)
{
double space = getValue() * .01;
cout << "Space before: " << space << "Mb" << "\n";
matrix a(dim, true, false);
matrix b(dim, true, false);
result std = run(mult_std, a, b);
matrix c(dim, true, true);
matrix d(dim, true, true);
result strassen = run(mult_strassen, c, d);
cout << "Dim " << " Std " << " Stranssen" << endl;
cout << dim << " " << std.second << "ms " << strassen.second << "ms " << "\n";
double spaceA = getValue() * .01;
cout << "Space: " << spaceA << "Mb" << "\n";
cout << " " << endl;
}
}
I set it to go from 1500 to 2300 by 200 and the program is "killed" before finishing
1500 2406 4250
1700 3463 4252
1900 4819 4247
2100 6487 30023
Killed
Also, it shouldn't make a big jump on time like that when the dimension goes from 1900 to 2100.

Matlab Spdiags equivalent in EIGEN C++

I'm searching for an equivalent of A=Spdiags(B,d,N,N)in C++. This function extracts the diagonals element of the matrix B by taking the columns of B and placing them along the diagonals specified by the vector d. N N are the size of the output matrix A.
I've searched in Eigen, but it seems that it does not exist.
any ideas?
There's no built in method as far as I know but it's not too hard to do this by building a new matrix via indices. Notice that the kth diagonal runs from index (max(1, 1-k), max(1, 1-k)+k) to (min(m, n-k), min(m, n-k)+k)
template <typename Scalar>
Eigen::SparseMatrix<Scalar> spdiags(const Matrix<Scalar, -1, -1>& B, const Eigen::Matrix<int, -1, 1>& d, size_t m, size_t n) {
Eigen::SparseMatrix<Scalar> A(m,n);
typedef Eigen::Triplet<Scalar> T;
std::vector<T> triplets;
triplets.reserve(std::min(m,n)*d.size());
for (int k = 0; k < d.size(); k++) {
int i_min = std::max(0, -d(k));
int i_max = std::min(m - 1, n - d(k) - 1);
int B_idx_start = m >= n ? d(k) : 0;
for (int i = i_min; i <= i_max; i++) {
triplets.push_back( T(i, i+k, B(B_idx_start + i, k)) );
}
}
A.setFromTriplets(triplets.begin(), triplets.end());
return A;
}
Note I haven't tested this but you get the idea. The first index into B is a little weird but I think it's right.
Other version, spdiags(A):
Eigen::MatrixXd spdiags(const Eigen::SparseMatrix<double>& A) {
// find nonzero diagonals by iterating over all nonzero elements
// d(i) = 1 if the ith diagonal of A contains a nonzero, 0 else
Eigen::VectorXi d = Eigen::VectorXi::Zero(A.rows() + A.cols() - 1);
for (int k=0; k < A.outerSize(); ++k) {
for (SparseMatrix<double>::InnerIterator it(A,k); it; ++it) {
d(it.col() - it.row() + A.rows() - 1) = 1;
}
}
int num_diags = d.sum();
Eigen::MatrixXd B(std::min(A.cols(), A.rows()), num_diags);
// fill B with diagonals
int B_col_idx = 0;
int B_row_sign = A.rows() >= A.cols() ? 1 : -1;
for (int i = 1 - A.rows(); i <= A.cols() - 1; i++) {
if (d(i + A.rows() - 1)) {
const auto& diag = A.diagonal(i);
int B_row_start = std::max(0, B_row_sign * i);
B.block(B_row_start, B_col_idx, diag.size(), 1) = diag;
B_col_idx++;
}
}
return B;
}
same disclaimer: haven't tested, but should work. Replace double with template <typename Scalar> as before if you want
here is a solution i've made. I've implemented the diagonal(i) because this function is not taken account by my eigen version (how can i know which version i use?). I obtain a good results with this, but i don't know if can more optimize it :
void spdiags(Eigen::SparseMatrix<double> A)
{
//Extraction of the diagnols before the main diagonal
vector<double> vec1; int flag=0;int l=0;
int i=0; int j=0; vector<vector<double> > diagD;
vector<vector<double> > diagG; int z=0; int z1=0;
for(int i=0;i<A.rows();i++)
{l=i;
do
{
if(A.coeff(l,j)!=0)
flag=1;
vec1.push_back(A.coeff(l,j));
l++;j++;
}while(l<A.rows() && j<A.cols());
if(flag==1) {diagG.resize(diagG.size()+1);diagG[z]=vec1; z++; }
vec1.clear(); l=0;j=0; flag=0; cout<<endl;
}
flag=0;z=0; vec1.clear();
// Extraction of the diagonals after the main diagonal
for(int i=1;i<A.cols();i++)
{l=i;
do
{
if(A.coeff(j,l)!=0)
flag=1;
vec1.push_back(A.coeff(j,l));
l++;j++;
}while(l<A.cols() && j<A.rows());
if(flag==1) {diagD.resize(diagD.size()+1);diagD[z]=vec1; z++; }
vec1.clear(); l=0;j=0; flag=0; cout<<endl;
}
// End extraction of the diagonals
Eigen::VectorXi d = Eigen::VectorXi::Zero(A.rows() + A.cols() - 1);
for (int k=0; k < A.outerSize(); ++k)
{
for (SparseMatrix<double>::InnerIterator it(A,k); it; ++it)
{
d(it.col() - it.row() + A.rows() - 1) = 1;
}
}
int num_diags = d.sum();
Eigen::MatrixXd B(std::min(A.cols(), A.rows()), num_diags);
// fill B with diagonals
Eigen::ArrayXd v;
int B_col_idx = 0;
int B_row_sign = A.rows() >= A.cols() ? 1 : -1;
int indG=diagG.size()-1; int indD=0;
for (int i = 1 - A.rows(); i <=A.cols() - 1; i++)
{
if (d(i + A.rows() - 1))
{
if(i<1)
{ v.resize(diagG[indG].size());
for(int i=0;i<diagG[indG].size();i++)
{
v(i)=diagG[indG][i];
}
int B_row_start = std::max(0, B_row_sign * i);
B.block(B_row_start, B_col_idx, diagG[indG].size(), 1) = v;
B_col_idx++;
indG--;
}
else
{
v.resize(diagD[indD].size());
for(int i=0;i<diagD[indD].size();i++)
{
v(i)=diagD[indD][i] ;
}
int B_row_start = std::max(0, B_row_sign * i);
B.block(B_row_start, B_col_idx, diagD[indD].size(), 1) = v;
B_col_idx++;
indD++;
}
}
}
cout<<B<<endl; //the result of the function
}//end of the function

TBB Reduction causes segfault when using more than 1 logical core

I implemented the Jacobi algorithm using TBB and it works just fine. Then I parallelized the convergence calculation using a reduction, but for some reason if I use more than 1 logical core I get an segmentation fault and i can't figure out why.
I can use more than 1 thread on a system that has only 1 logical core.
The same implementation using OpenMP works without a hassle
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_reduce.h>
#include <tbb/blocked_range.h>
#include <tbb/task_scheduler_init.h>
#include <tbb/tick_count.h>
// ----------------------------------------------------------------
#define SIZE 1024
#define RESIDUO 0.0009f*SIZE
#define THREADS 2
using namespace tbb;
// ----------------------------------------------------------------
struct Sum {
float ret;
float (*a)[SIZE];
float (*x);
float (*b);
Sum(float A[SIZE][SIZE], float X[SIZE], float B[SIZE]) : ret(0), a(A), x(X), b(B) {}
Sum( Sum&, split ) {ret = 0;}
void operator()( const blocked_range<int>& r ) {
float temp = ret;
for( int i = r.begin(); i != r.end(); i++ ) {
float sum = 0.0f;
for(int j = 0; j < SIZE; j++){
sum += a[i][j] * x[j];
}
temp += pow(b[i] - sum, 2);
}
ret = temp;
}
void join( Sum& rhs ) {ret += rhs.ret;}
};
/*
// || b - Ax ||
*/
int converge(float a[SIZE][SIZE], float x[SIZE], float b[SIZE]){
Sum total(a, x, b);
parallel_reduce( blocked_range<int>(0, SIZE), total );
float norm = sqrt(total.ret);
printf("Ret: %f | Residuo: %f\n", total.ret, norm);
return (norm <= RESIDUO);
}
// ----------------------------------------------------------------
float randomFloat()
{
float r = (float)rand()/(float)RAND_MAX;
return r;
}
// ----------------------------------------------------------------
int check_ddm(float (*a)[SIZE]){
float sum = 0.0f;
int i = 0, j = 0;
for(i = 0; i < SIZE; i++){
sum = 0.0f;
for(j = 0; j < SIZE; j++){
if(i != j){
sum += a[i][j];
}
}
if(a[i][i] < sum){
printf("line: %d, sum: %f, a[i][i]: %f \n", i, sum, a[i][i]);
for(j = 0; j < SIZE; j++){
if(i != j) printf("%f ", a[i][j]);
else printf("(%f) ", a[i][j]);
}
printf("\n");
return 0;
}
}
return 1;
}
// ----------------------------------------------------------------
int generate_ddm(float (*a)[SIZE], float *b)
{
int i = 0, j = 0;
float line = 0.0f;
for(i = 0; i < SIZE; i++){
line = 0.0f;
for(j = 0; j < SIZE; j++){
if(i != j){
a[i][j] = randomFloat();
}
line += a[i][j];
}
a[i][i] = SIZE;
b[i] = line + SIZE;
}
return check_ddm(a);
}
// ----------------------------------------------------------------
int main( )
{
float (*x)[SIZE] = (float(*)[SIZE])malloc(sizeof *x * 2);
float (*a)[SIZE] = (float(*)[SIZE])malloc(sizeof *a * SIZE);
float (*b) = (float*)malloc(sizeof(float) * SIZE);
int i = 0, j = 0;
float delta = 0.0f;
int read = 0;
int write = 1;
srand(time(NULL));
tbb::task_scheduler_init init(THREADS);
// set up initial solution
for(i = 0; i < SIZE; i++){
x[0][i] = i;
x[1][i] = i;
}
// generate a diagonal dominant matrix
if(!generate_ddm(a, b)){
printf("Array generated is not ddm!\n");
return 1;
}
tick_count startTime = tick_count::now();
while(!converge(a, x[write], b)){
read = !read;
write = !write;
parallel_for(blocked_range<int>(0,SIZE),
[&] (const blocked_range<int>& r) {
for (int i = r.begin(); i < r.end(); i++) {
float delta = 0.0f;
for(int j = 0; j < SIZE; j++){
if(j != i){
delta += a[i][j] * x[read][j];
}
}
x[write][i] = (b[i] - delta) / a[i][i];
}
});
}
tick_count lastTime = tick_count::now();
float walltime = (lastTime - startTime).seconds();
printf("tbb %f\n", walltime);
converge(a, x[write], b);
printf("x0: %f | x%d: %f\n", x[write][0], SIZE-1, x[write][SIZE-1]);
free(a);
free(b);
free(x);
return 0;
}
The segfault occurs on the following line inside the Sum class:
sum += a[i][j] * x[j];
And if I change that line to
float tmpa = a[i][j];
float tmpx = x[j];
sum += tmpa * tmpx;
The error continues to be on
sum += tmpa * tmpx;
In the original version, the "splitting constructor" left a, x, and b undefined. They need to be copied from the incoming Sum& argument. E.g., change the splitting constructor to:
Sum( Sum& s, split ) {a=s.a; b=s.b; x=s.x; ret = 0;}
Changing the Class to a lambda expression solved the problem. It maybe a bug in TBB's parallel_reduce
int converge(float a[SIZE][SIZE], float x[SIZE], float b[SIZE]){
float val = 0.0f;
val = parallel_reduce(
blocked_range<int>(0, SIZE),
0.0f,
[&]( const blocked_range<int>& r, float init )->float {
float temp = init;
for(int i = r.begin(); i != r.end(); i++ ) {
float sum = 0.0f;
for(int j = 0; j < SIZE; j++){
sum += a[i][j] * x[j];
}
temp += pow(b[i] - sum, 2);
}
return temp;
},
[]( float x, float y)->float{
return x+y;
}
);
float norm = sqrt(val);
printf("Ret: %f | Residuo: %f\n", val, norm);
return (norm <= RESIDUO);
}

Trouble with a namespace in a header file, "undefined reference to" error?

I'm getting the following errors due to the namespace cpl?
I included Wavepacket.cpp and Vector.hpp below.
obj\Debug\wavepacket.o||In function `Z10initializev':|
wavepacket.cpp|79|undefined reference to `cpl::Vector::Vector(int)'|
wavepacket.cpp|79|undefined reference to `cpl::Vector::operator=(cpl::Vector const&)'|
wavepacket.cpp|80|undefined reference to `cpl::ComplexVector::ComplexVector(int)'|
wavepacket.cpp|80|undefined reference to `cpl::ComplexVector::operator=(cpl::ComplexVector const&)'|
wavepacket.cpp|81|undefined reference to `cpl::ComplexVector::ComplexVector(int)'|
wavepacket.cpp|81|undefined reference to `cpl::ComplexVector::operator=(cpl::ComplexVector const&)'|
wavepacket.cpp|101|undefined reference to `cpl::ComplexVector::ComplexVector(int)'|
wavepacket.cpp|101|undefined reference to `cpl::ComplexVector::operator=(cpl::ComplexVector const&)'|
wavepacket.cpp|102|undefined reference to `cpl::ComplexVector::ComplexVector(int)'|
wavepacket.cpp|102|undefined reference to `cpl::ComplexVector::operator=(cpl::ComplexVector const&)'|
wavepacket.cpp|103|undefined reference to `cpl::ComplexVector::ComplexVector(int)'|
wavepacket.cpp|103|undefined reference to `cpl::ComplexVector::operator=(cpl::ComplexVector const&)'|
obj\Debug\wavepacket.o||In function `Z8timeStepv':|
wavepacket.cpp|124|undefined reference to `cpl::solveTridiagonalCyclic(cpl::ComplexVector&, cpl::ComplexVector&, cpl::ComplexVector&, std::complex<double>, std::complex<double>, cpl::ComplexVector&, cpl::ComplexVector&)'|
wavepacket.cpp|126|undefined reference to `cpl::solveTridiagonal(cpl::ComplexVector&, cpl::ComplexVector&, cpl::ComplexVector&, cpl::ComplexVector&, cpl::ComplexVector&)'|
obj\Debug\wavepacket.o||In function `_static_initialization_and_destruction_0':|
wavepacket.cpp|22|undefined reference to `cpl::Vector::Vector(int)'|
wavepacket.cpp|71|undefined reference to `cpl::ComplexVector::ComplexVector(int)'|
wavepacket.cpp|71|undefined reference to `cpl::ComplexVector::ComplexVector(int)'|
wavepacket.cpp|72|undefined reference to `cpl::ComplexVector::ComplexVector(int)'|
wavepacket.cpp|72|undefined reference to `cpl::ComplexVector::ComplexVector(int)'|
wavepacket.cpp|72|undefined reference to `cpl::ComplexVector::ComplexVector(int)'|
||=== Build finished: 20 errors, 0 warnings ===|
Wavepacket.cpp
#include <cmath>
#include <complex>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <string>
#include <sstream>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include "Vector.hpp"
const double pi = 4*std::atan(1.0);
double h_bar = 1; // natural units
double mass = 1; // natural units
// The spatial grid
int N = 200; // number of interior grid points
double L = 100; // system extends from x=0 to x=L
double h = L / (N + 1); // grid size
double tau = 1; // time step
cpl::Vector x; // coordinates of grid points
bool periodic = true; // false = oo potential, true = periodic
// The potential V(x)
double V0 = 1.0; // height of potential well
double Vwidth = 10; // width of potential well
double Vcenter = 0.75 * L; // center of potential well
bool gaussian; // false = step potential
double V(double x) {
double halfWidth = std::abs(0.5 * Vwidth);
if (gaussian) {
double dx = (x - Vcenter) / halfWidth;
return V0 * std::exp( - dx * dx / 2);
} else {
if (std::abs(x - Vcenter) <= halfWidth)
return V0;
else
return 0;
}
}
// Inital wave packet
double x0 = L / 4; // location of center
double E = 1; // average energy
double sigma0 = L / 10; // width of wave packet
double Norm_psi; // norm of psi
double k0; // average wavenumber
double velocity; // average velocity
void getInput() {
std::cout << "Time-dependent Schroedinger Equation\n";
std::cout << "Enter size of x region L = ";
std::cin >> L;
std::cout << "Enter number of grid points N = ";
std::cin >> N;
std::cout << "Enter integration time step tau = ";
std::cin >> tau;
std::cout << "Enter width of potential = ";
std::cin >> Vwidth;
std::cout << "Enter height of potential V0 = ";
std::cin >> V0;
std::cout << "Enter width of packet sigma = ";
std::cin >> sigma0;
std::cout << "Enter energy of packet E = ";
std::cin >> E;
}
double t; // time
cpl::ComplexVector psi, chi; // complex wavefunction
cpl::ComplexVector a, b, c; // to represent tridiagonal Q matrix
std::complex<double> alpha, beta; // corner elements of Q
void initialize () {
t = 0;
// reset vectors
x = cpl::Vector(N);
psi = cpl::ComplexVector(N);
chi = cpl::ComplexVector(N);
// reset the lattice
h = L / (N + 1);
for (int j = 0; j < N; j++)
x[j] = (j + 1) * h;
// inititalize the packet
k0 = std::sqrt(2*mass*E - h_bar*h_bar/2/sigma0/sigma0) / h_bar;
velocity = k0 / mass;
Norm_psi = 1 / std::sqrt(sigma0 * std::sqrt(pi));
for (int j = 0; j < N; j++) {
double expFactor = std::exp(-(x[j] - x0) * (x[j] - x0)
/ (2 * sigma0 * sigma0));
psi[j] = std::complex<double>(
Norm_psi * std::cos(k0 * x[j]) * expFactor,
Norm_psi * std::sin(k0 * x[j]) * expFactor);
}
// elements of tridiagonal matrix Q = (1/2)(1 + i tau H / (2 hbar))
a = cpl::ComplexVector(N);
b = cpl::ComplexVector(N);
c = cpl::ComplexVector(N);
for (int j = 0; j < N; j++) {
const std::complex<double> i(0.0, 1.0);
b[j] = 0.5 + i * tau / (4 * h_bar) *
(V(x[j]) + h_bar * h_bar / (mass * h * h));
a[j] = c[j] = - i * tau * h_bar / (8 * mass * h * h);
}
alpha = c[N-1];
beta = a[0];
}
double T = 5; // time to travel length L
double framesPerSec = 50; // animation rate for screen redraws
void timeStep() {
static std::clock_t clockStart;
static bool done;
if (!done) {
double t0 = t;
do {
if (periodic)
solveTridiagonalCyclic(a, b, c, alpha, beta, psi, chi);
else
solveTridiagonal(a, b, c, psi, chi);
for (int j = 0; j < N; j++)
psi[j] = chi[j] - psi[j];
t += tau;
} while (std::abs(velocity * (t - t0)) < L / T / framesPerSec);
done = true;
}
std::clock_t clockNow = std::clock();
double seconds = (clockNow - clockStart) / double(CLOCKS_PER_SEC);
if ( seconds < 1 / framesPerSec ) {
return;
} else {
clockStart = clockNow;
done = false;
}
glutPostRedisplay();
glFlush();
}
void drawText(const std::string& str, double x, double y) {
glRasterPos2d(x, y);
int len = str.find('\0');
for (int i = 0; i < len; i++)
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, str[i]);
}
bool showRealImaginary; // false = probability only
void display() {
glClear(GL_COLOR_BUFFER_BIT);
if (showRealImaginary) {
glColor3f(0, 0, 1); // real part of psi blue
glBegin(GL_LINES);
for (int j = 1; j < N; j++) {
glVertex2d(x[j-1], psi[j-1].real());
glVertex2d(x[j], psi[j].real());
}
glEnd();
glColor3f(0, 1, 0); // imaginary part of psi green
glBegin(GL_LINES);
for (int j = 1; j < N; j++) {
glVertex2d(x[j-1], psi[j-1].imag());
glVertex2d(x[j], psi[j].imag());
}
glEnd();
}
glColor3f(1, 0, 0); // probability red
double pOld = psi[0].real() * psi[0].real() +
psi[0].imag() * psi[0].imag();
glBegin(GL_LINES);
for (int j = 1; j < N; j++) {
double p = psi[j].real() * psi[j].real() +
psi[j].imag() * psi[j].imag();
glVertex2d(x[j-1], 4 * pOld);
glVertex2d(x[j], 4 * p);
pOld = p;
}
glEnd();
glColor3ub(255, 165, 0); // potential orange
double Vold = V(x[1]);
glBegin(GL_LINES);
for (int j = 1; j < N; j++) {
double Vnew = V(x[j]);
glVertex2d(x[j-1], 0.2 * Vold);
glVertex2d(x[j], 0.2 * Vnew);
Vold = Vnew;
}
glEnd();
glColor3f(0, 0, 0); // text black
std::ostringstream os;
os << (periodic ? "Periodic " : "Infinite Wall ")
<< "Boundary Conditions" << std::ends;
drawText(os.str(), 0.02 * L, 0.28);
os.seekp(0); // beginning of string stream
os << "0" << std::ends;
drawText(os.str(), 0, -0.02);
drawText("0", 0, -0.02);
os.seekp(0);
os << "x = " << L << std::ends;
drawText(os.str(), (1 - 0.1) * L, -0.02);
os.seekp(0);
os << "t = " << t << std::ends;
drawText(os.str(), 0.02 * L, -0.29);
glutSwapBuffers();
}
void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, L, -0.3, 0.3);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
bool running; // to control animation
void mouse(int button, int state, int x, int y) {
switch (button) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
if (running) {
glutIdleFunc(NULL);
running = false;
} else {
glutIdleFunc(timeStep);
running = true;
}
}
break;
default:
break;
}
}
void menu(int menuItem) {
switch (menuItem) {
case 1:
gaussian = !gaussian;
break;
case 2:
periodic = !periodic;
break;
case 3:
showRealImaginary = !showRealImaginary;
break;
case 4:
if (running) {
glutIdleFunc(NULL);
running = false;
}
initialize();
glutPostRedisplay();
break;
default:
break;
}
}
int main(int argc, char *argv[]) {
getInput();
initialize();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(600, 400);
glutInitWindowPosition(100, 100);
glutCreateWindow("Schroedinger Wave Packet Motion");
glClearColor(1.0, 1.0, 1.0, 0.0);
glShadeModel(GL_FLAT);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutCreateMenu(menu);
glutAddMenuEntry("Potential: Square/Gaussian", 1);
glutAddMenuEntry("Boundaries: Dirichlet/Periodic", 2);
glutAddMenuEntry("Real & Imag: Show/Hide", 3);
glutAddMenuEntry("Reset", 4);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutMainLoop();
}
Vector.hpp
#ifndef CPL_VECTOR_HPP
#define CPL_VECTOR_HPP
#include <complex>
#include <iostream>
namespace cpl {
class Vector {
public:
Vector(int dim = 1);
Vector(const Vector& dv);
~Vector() { delete [] v; }
int dimension() const { return dim; }
void resize(const int);
const double operator[](const int i) const { return v[i]; }
double& operator[](const int i) { return v[i]; }
Vector& operator = (const Vector& dv);
Vector& operator += (const Vector& dv);
Vector& operator -= (const Vector& dv);
Vector& operator *= (double d);
Vector& operator /= (double d);
double abs();
double norm();
double dot(const Vector& dv);
friend std::ostream& operator<<(std::ostream& os, const Vector& dv);
private:
int dim;
double *v;
};
inline Vector operator + (const Vector& dv) {
return dv;
}
extern Vector operator - (const Vector& dv);
extern Vector operator * (const Vector& dv, double d);
extern Vector operator * (double d, const Vector& dv);
extern Vector operator / (const Vector& dv, double d);
extern Vector operator + (const Vector& v1, const Vector& v2);
extern Vector operator - (const Vector& v1, const Vector& v2);
class ComplexVector {
public:
ComplexVector(int dim = 1);
ComplexVector(const ComplexVector& cv);
~ComplexVector() { delete [] v; }
int dimension() const { return dim; }
const std::complex<double> operator[](const int i) const { return v[i]; }
std::complex<double>& operator[](const int i) { return v[i]; }
ComplexVector& operator = (const ComplexVector& cv);
private:
int dim;
std::complex<double> *v;
};
class FFT {
public:
FFT() { N = 0; f = 0; inverse = false; }
void transform(ComplexVector& data);
void inverseTransform(ComplexVector& data);
Vector power(ComplexVector& data);
private:
int N;
ComplexVector *f;
bool inverse;
void bitReverse();
void DanielsonLanczos(int n);
};
extern void solveTridiagonal(
ComplexVector& a, ComplexVector& b, ComplexVector& c,
ComplexVector& r, ComplexVector& u);
extern void solveTridiagonalCyclic(
ComplexVector& a, ComplexVector& b, ComplexVector& c,
std::complex<double> alpha, std::complex<double> beta,
ComplexVector& r, ComplexVector& x);
} /* end namespace cpl */
#endif /* CPL_VECTOR_HPP */
EDIT I didn't want to delete this post incase someone needed it but I forgot to use Vector.cpp which is below.
#include "Vector.hpp"
namespace cpl {
Vector::Vector(int dim) {
v = new double [this->dim = dim];
for (int i = 0; i < dim; i++) v[i] = 0;
}
Vector::Vector(const Vector& dv) {
v = new double [dim = dv.dim];
for (int i = 0; i < dim; i++) v[i] = dv.v[i];
}
void Vector::resize(const int dimension) {
delete [] v;
v = new double [dim = dimension];
for (int i = 0; i < dim; i++) v[i] = 0;
}
Vector& Vector::operator = (const Vector& dv) {
if (this != &dv) {
if (dim != dv.dim) {
delete [] v;
v = new double [dim = dv.dim];
}
for (int i = 0; i < dim; i++) v[i] = dv[i];
}
return *this;
}
Vector& Vector::operator += (const Vector& dv) {
for (int i = 0; i < dim; i++) v[i] += dv[i];
return *this;
}
Vector& Vector::operator -= (const Vector& dv) {
for (int i = 0; i < dim; i++) v[i] -= dv[i];
return *this;
}
Vector& Vector::operator *= (double d) {
for (int i = 0; i < dim; i++) v[i] *= d;
return *this;
}
Vector& Vector::operator /= (double d) {
for (int i = 0; i < dim; i++) v[i] /= d;
return *this;
}
Vector operator - (const Vector& dv) {
int dim = dv.dimension();
Vector temp(dim);
for (int i = 0; i < dim; i++) temp[i] = -dv[i];
return temp;
}
Vector operator * (const Vector& dv, double d) {
int dim = dv.dimension();
Vector temp(dim);
for (int i = 0; i < dim; i++) temp[i] = dv[i] * d;
return temp;
}
Vector operator * (double d, const Vector& dv) {
int dim = dv.dimension();
Vector temp(dim);
for (int i = 0; i < dim; i++) temp[i] = dv[i] * d;
return temp;
}
Vector operator / (const Vector& dv, double d) {
int dim = dv.dimension();
Vector temp(dim);
for (int i = 0; i < dim; i++) temp[i] = dv[i] / d;
return temp;
}
Vector operator + (const Vector& v1, const Vector& v2) {
int dim = v1.dimension();
Vector temp(dim);
for (int i = 0; i < dim; i++) temp[i] = v1[i] + v2[i];
return temp;
}
Vector operator - (const Vector& v1, const Vector& v2) {
int dim = v1.dimension();
Vector temp(dim);
for (int i = 0; i < dim; i++) temp[i] = v1[i] - v2[i];
return temp;
}
double Vector::abs() {
return std::sqrt(norm());
}
double Vector::norm() {
double sum = 0;
for (int i = 0; i < dim; i++) sum += v[i] * v[i];
return sum;
}
double Vector::dot(const Vector& dv) {
double sum = 0;
for (int i = 0; i < dim; i++) sum += v[i] * dv[i];
return sum;
}
std::ostream& operator<<(std::ostream& os, const Vector& dv) {
for (int i = 0; i < dv.dim; i++) {
os << dv.v[i];
if (i < dv.dim-1)
os << '\t';
else
os << '\n';
}
return os;
}
// ComplexVector implementation
ComplexVector::ComplexVector(int dim) {
v = new std::complex<double> [this->dim = dim];
for (int i = 0; i < dim; i++) v[i] = 0.0;
}
ComplexVector::ComplexVector(const ComplexVector& cv) {
v = new std::complex<double> [dim = cv.dim];
for (int i = 0; i < dim; i++) v[i] = cv.v[i];
}
ComplexVector& ComplexVector::operator = (const ComplexVector& cv) {
if (this != &cv) {
if (dim != cv.dim) {
delete [] v;
v = new std::complex<double> [dim = cv.dim];
}
for (int i = 0; i < dim; i++) v[i] = cv[i];
}
return *this;
}
// FFT implementation
void FFT::transform(ComplexVector& data) {
N = data.dimension();
f = &data;
bitReverse();
for (int n = 1; n < N; n *= 2)
DanielsonLanczos(n);
for (int i = 0; i < N; ++i)
(*f)[i] /= std::sqrt(double(N));
}
void FFT::inverseTransform(ComplexVector& data) {
inverse = true;
transform(data);
inverse = false;
}
void FFT::bitReverse() {
int j = 1;
for (int i = 1; i < N; ++i) {
if (i < j) {
std::complex<double> temp = (*f)[i-1];
(*f)[i-1] = (*f)[j-1];
(*f)[j-1] = temp;
}
int k = N / 2;
while ( k < j ) {
j -= k;
k /= 2;
}
j += k;
}
}
void FFT::DanielsonLanczos(int n) {
const double pi = 4 * atan(1.0);
std::complex<double> W(0, pi / n);
W = inverse ? std::exp(-W) : std::exp(W);
std::complex<double> W_j(1, 0);
for (int j = 0; j < n; ++j) {
for (int i = j; i < N; i += 2 * n) {
std::complex<double> temp = W_j * (*f)[n+i];
(*f)[n+i] = (*f)[i] - temp;
(*f)[i] += temp;
}
W_j *= W;
}
}
Vector FFT::power(ComplexVector& data) {
Vector P(1 + N / 2);
P[0] = std::norm(data[0]) / double(N);
for (int i = 1; i < N / 2; i++)
P[i] = (std::norm(data[i]) + std::norm(data[N-i])) / double(N);
P[N/2] = std::norm(data[N/2]) / double(N);
return P;
}
// Solving tridiagonal complex matrices
void solveTridiagonal(
ComplexVector& a, ComplexVector& b, ComplexVector& c,
ComplexVector& r, ComplexVector& u)
{
int n = a.dimension();
ComplexVector gamma(n);
std::complex<double> beta = b[0];
u[0] = r[0] / beta;
for (int j = 1; j < n; j++) {
gamma[j] = c[j-1] / beta;
beta = b[j] - a[j] * gamma[j];
u[j] = (r[j] - a[j] * u[j-1]) / beta;
}
for (int j = n - 2; j >= 0; j--)
u[j] -= gamma[j+1] * u[j+1];
}
void solveTridiagonalCyclic(
ComplexVector& a, ComplexVector& b, ComplexVector& c,
std::complex<double> alpha, std::complex<double> beta,
ComplexVector& r, ComplexVector& x)
{
int n = a.dimension();
ComplexVector bb(n), u(n), z(n);
std::complex<double> gamma = -b[0];
bb[0] = b[0] - gamma;
bb[n-1] = b[n-1] - alpha * beta / gamma;
for (int i = 1; i < n-1; i++)
bb[i] = b[i];
solveTridiagonal(a, bb, c, r, x);
u[0] = gamma;
u[n-1] = alpha;
for (int i = 1; i < n-1; i++)
u[i] = 0.0;
solveTridiagonal(a, bb, c, u, z);
std::complex<double> fact = x[0] + beta * x[n-1] / gamma;
fact /= 1.0 + z[0] + beta * z[n-1] / gamma;
for (int i = 0; i < n; i++)
x[i] -= fact * z[i];
}
} /* end namespace cpl */
it's probably your build script that's not configured correctly. Your code compiled for me when I used the following commands:
g++ -c Vector.cpp -o Vector.o
g++ -c Wavepacket.cpp -o Wavepacket.o
g++ Vector.o Wavepacket.o -lGL -lGLU -lglut -o app