I'm using viennacl to solve a linear system of equations (AX = B) with the graphic card. Also, the code uses armadillo.
My system of equations have complex numbers. So the question is: Can I solve a system of equations (with complex numbers) using viennacl?
Above is an example of a working code with real numbers.
// System headers
#include <iostream>
// Armadillo headers (disable BLAS and LAPACK to avoid linking issues)
#define ARMA_DONT_USE_BLAS
#define ARMA_DONT_USE_LAPACK
#include <armadillo>
#include <complex>
#define VIENNACL_WITH_ARMADILLO 1
// ViennaCL headers
#include "viennacl/linalg/cg.hpp"
#include "viennacl/linalg/bicgstab.hpp"
#include "viennacl/linalg/gmres.hpp"
#include "viennacl/io/matrix_market.hpp"
#include "vector-io.hpp"
//using namespace arma;
using namespace viennacl::linalg;
using namespace std;
typedef arma::mat armat;
typedef arma::vec arvec;
typedef complex<double> dcmplx;
int main(void)
{
int N = 500;
armat A(N,N);
A.randu();
arvec B(N);
B.randu();
arvec X(N);
arvec residual(N);
viennacl::matrix<double> vcl_A(N, N);
viennacl::vector<double> vcl_B(N);
viennacl::vector<double> vcl_X(N);
viennacl::vector<double> vcl_result(N);
viennacl::copy(A, vcl_A);
viennacl::copy(B, vcl_B);
viennacl::copy(X, vcl_X);
std::cout << "----- Running GMRES -----" << std::endl;
vcl_X = viennacl::linalg::solve(vcl_A, vcl_B, viennacl::linalg::gmres_tag());
viennacl::copy(vcl_A, A);
viennacl::copy(vcl_B, B);
viennacl::copy(vcl_X, X);
residual = A * X - B;
cout << "Relative residual: " << norm(residual) / norm(B) << endl;
}
Complex version of the code:
#include <iostream>
// Armadillo headers (disable BLAS and LAPACK to avoid linking issues)
#define ARMA_DONT_USE_BLAS
#define ARMA_DONT_USE_LAPACK
#include <armadillo>
#include <complex>
#define VIENNACL_WITH_ARMADILLO 1
// ViennaCL headers
#include "viennacl/linalg/cg.hpp"
#include "viennacl/linalg/bicgstab.hpp"
#include "viennacl/linalg/gmres.hpp"
#include "viennacl/io/matrix_market.hpp"
#include "vector-io.hpp"
//using namespace arma;
using namespace viennacl::linalg;
using namespace std;
typedef arma::cx_mat armat;
typedef arma::cx_vec arvec;
typedef complex<double> dcmplx;
int main(void)
{
int N = 500;
armat A(N,N);
A.randu();
arvec B(N);
B.randu();
arvec X(N);
arvec residual(N);
viennacl::matrix<dcmplx> vcl_A(N, N);
viennacl::vector<dcmplx> vcl_B(N);
viennacl::vector<dcmplx> vcl_X(N);
viennacl::vector<dcmplx> vcl_result(N);
viennacl::copy(A, vcl_A);
viennacl::copy(B, vcl_B);
viennacl::copy(X, vcl_X);
std::cout << "----- Running GMRES -----" << std::endl;
vcl_X = viennacl::linalg::solve(vcl_A, vcl_B, viennacl::linalg::gmres_tag());
viennacl::copy(vcl_A, A);
viennacl::copy(vcl_B, B);
viennacl::copy(vcl_X, X);
residual = A * X - B;
cout << "Relative residual: " << norm(residual) / norm(B) << endl;
std::cout << "----- Running BiCGStab -----" << std::endl;
vcl_X = viennacl::linalg::solve(vcl_A, vcl_B, viennacl::linalg::bicgstab_tag());
viennacl::copy(vcl_A, A);
viennacl::copy(vcl_B, B);
viennacl::copy(vcl_X, X);
residual = A * X - B;
cout << "Relative residual: " << norm(residual) / norm(B) << endl;
std::cout << "----- Running CG -----" << std::endl;
vcl_X = viennacl::linalg::solve(vcl_A, vcl_B, viennacl::linalg::cg_tag());
viennacl::copy(vcl_A, A);
viennacl::copy(vcl_B, B);
viennacl::copy(vcl_X, X);
residual = A * X - B;
cout << "Relative residual: " << norm(residual) / norm(B) << endl;
}
ViennaCL currently does not support complex numbers. The primary technical reason is that OpenCL does not natively provide support for complex numbers. While emulating complex arithmetic via real arithmetic is certainly possible, we were reluctant to go down this path and (wrongly?) hoped that a standardization for complex will come soon.
Related
I want to expose generic Timer. The problem is I don't know why extern got underlined with red and the Visual Studio 2019 Community says "linking specification is not allowed".
Question
What is the correct syntax for extern?
Minimal Working Example
The header utilities.hpp:
#pragma once
#ifdef UTILITIES_EXPORTS
#define UTILITIES_API __declspec(dllexport)
#else
#define UTILITIES_API __declspec(dllimport)
#endif
namespace Utilities
{
template<typename F>
extern "C" UTILITIES_API void Timer(F f, unsigned int N = 1);
}
The definition file utilities.cpp:
#include "Timer.h"
#include <iostream>
#include <vector>
#include <chrono>
#include <iomanip>
using namespace std;
namespace Utilities
{
template<typename F>
void Timer(F f, unsigned int N)
{
cout << fixed << setprecision(9);
vector<unsigned int> results;
const double million = 1'000'000'000.0;
for (unsigned int i = 0; i < N; i++)
{
chrono::steady_clock::time_point begin = chrono::steady_clock::now();
f();
chrono::steady_clock::time_point end = chrono::steady_clock::now();
unsigned int interval = chrono::duration_cast<chrono::nanoseconds>(end - begin).count();
results.push_back(interval);
double elapsedTime = interval / million;
cout << "Elapsed: \t\t" << elapsedTime << " s." << endl;
}
unsigned long long sum = 0;
for (unsigned int x : results)
sum += x;
double totalElapsedTime = sum / million / results.size();
cout << "\t\t\tAverage elapsed: " << totalElapsedTime << " s." << endl;
}
}
The compiler has to know what types you use with the generic, because it basically has to make a copy of Timer that works with that type.
For an extern method, there is no way to know this, and it would have to be evaluated at runtime, which is not how generics work. It's a compiler feature.
You can make a wrapper for a specific type and make that extern.
I'm trying to figure out if this is a bug in Eigen or something I'm doing wrong. I simply want the dot product of two complex vectors [ 1 , i] and [1 , -i]. The answer is 1*1 + i*(-i) = 2. But Eigen gives zero as answer. See code below:
#include <iostream>
#include <sstream>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <map>
#include <sys/sysinfo.h>
#include <algorithm>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main( void ){
VectorXcd xd0(2);
complex<double> c_i( 0.0 , 1.0 );
xd0[0] = 1.0 ;
xd0[1] = c_i;
VectorXcd xd0conj = xd0.conjugate();
cout <<" vec is \n" << xd0 <<endl;
cout <<" conj vec is \n" << xd0conj <<endl;
cout << "eigen dot = " << (xd0conj).dot(xd0 ) <<endl;
complex<double> outVal = 0.0;
for( int a=0; a<xd0.size(); a++){
outVal += xd0[a]*xd0conj[a];
}
cout << "naive dot = " << outVal<<endl;
};
From the documentation:
"
If the scalar type is complex numbers, then this function returns the hermitian (sesquilinear) dot product, conjugate-linear in the first variable and linear in the second variable.
"
This product is often used, for example in quantum mechanics.
It computes conj(x)*y which is what you are seeing. I guess you want the simple / ordinary dot:
cout << "eigen dot = " << xd0conj.transpose()*xd0 <<endl;
This outputs
eigen dot = (2,0)
I am a beginner of C++. Any help will be very appreciated!
I can successfully compile and run the following code:
#include <Eigen/Dense>
#include <iostream>
#include <cmath>
using namespace Eigen;
int main()
{
MatrixXf m1(10,1);
m1 << 50,51,52,54,53,60,59,65,67,70;
MatrixXf m3(3,10);
MatrixXf m2(10,3);
m3<< 1,1,1,1,1,1,1,1,1,1, //Xf[,5:6]
54,61,52,70,63,0,0,0,0,0,
0,0,0,0,0,79,68,65,79,76;
m2 << m3.transpose();
MatrixXf I(10,10);
I.setIdentity(10,10);
float SSE =(m1.transpose()*(I-m2*(m2.transpose()*m2).inverse()*m2.transpose())*m1).determinant();
std::cout << "SSE=" << std::endl;
std::cout << SSE << std::endl << std::endl;
system("pause");
}
SSE worked out in C++:87.7938,while SSE true value:88.29133
You need to use MatrixXd instead of MatrixXf
I have a problem using atof,
here is the code:
#include <stdio.h>
#include <cstdlib>
#include <iostream>
#include <string>
using namespace std;
int main(){
std::string num ("1.0");
//std::string num ("1.1");
cout<< atof(num.c_str());
return 0;
}
If the num string is "1.1" , it can correctly cout 1.1. But if I want to keep the zero when the num string is "1.0" (want it to be 1.0 but not 1), what should I do?
You need to use std::fixed and std::setprecision, like so:
std::cout<< std::fixed << std::setprecision(1) << atof(num.c_str());
This will require that you include the iomanip header.
A possible solution is
#include <cstdio>
#include <iostream>
#include <string>
#include <iomanip>
int main() {
std::cout.precision(3);
std::cout.setf(std::ios::fixed);
std::string s("1.0");
float f = 0.0f;
sscanf(s.c_str(), "%f", &f);
// alternative way of setting this flags
// std::cout << std::fixed << std::setprecision(3) << f << "\n";
std::cout << f << "\n";
return (0);
}
notice that there are at least 2 ways of accomplishing the same format for the output, I left one of them commented out .
I have a vector of data and I want to find the kurtosis of the data set. I wanted to do so with Boost and here is what I have so far (not compilable):
#include <boost/math/distributions.hpp>
using namespace std;
int main()
{
vector<double> a;
a.push_back(-1);
a.push_back(0);
a.push_back(1);
cout << "Kurtosis:"<< kurtosis(a) << endl;
return 0;
}
Why doesn't this work? My compiler gives me the error: "[...]\main.cpp|28|error: 'kurtosis' was not declared in this scope|"
For one you were not including the header for kurtosis:
#include <boost/accumulators/statistics/kurtosis.hpp>
Even if you did, as you see it does not work with a straight vector, what you probably want to do is use an accumulator_set and more headers as well.
Here is a minimal example using accumulator_set, this shows a two methods to solve the problem:
#include <boost/math/distributions.hpp>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/variance.hpp>
#include <boost/accumulators/statistics/kurtosis.hpp>
#include <iostream>
#include <vector>
using namespace boost::accumulators;
int main()
{
accumulator_set<double, stats<tag::mean, tag::kurtosis > > acc;
accumulator_set<double, stats<tag::mean, tag::kurtosis > > acc2;
acc(2) ;
acc(3) ;
acc(4) ;
std::cout << mean(acc) << " " << kurtosis(acc) << std::endl ;
std::vector<double> v1 ;
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
acc2 = std::for_each( v1.begin(), v1.end(), acc2 ) ;
std::cout << mean(acc2) << " " << kurtosis(acc2) << std::endl ;
}
Here is a link to the Accumulators Framework User's Guide. This guide has some nice examples.
This previous thread found a way to use vector, although it is not straight forward at all and I could not get it work.