So I'm trying to code Dijkstra's shortest path algorithm in C++. For some reason, it's not adding up the distances correctly...
Here is what I have so far for code. You can ignore the section where I am copying the path to the stack because I know it's not complete yet. Any ideas where I'm going wrong?
#include <fstream>
#include "matrix.h"
#include <list> // STL container
using namespace std;
//---------------------------------------------------------------------------
const int INFIN = 100000;
const int size = 8;
double a[] = {
0, 0, 5, 0, 0, 2, 3, 0, //length matrix ( #9, page 276)
4, 0, 6, 0, 7, 0, 5, 0,
0, 3, 0, 9, 2, 6, 0, 7,
3, 0, 2, 0, 1, 0, 7, 6,
0, 5, 0, 1, 0, 0, 4, 0,
0, 0, 2, 0, 8, 0, 9, 0,
1, 2, 3, 0, 0, 6, 0, 0,
5, 0, 8, 0, 2, 0, 9, 0
};
// Global declarations for L Matrix and begin and end node
Matrix L(size,size,a); //length matrix
int begin, end;
void path(long* D, int* P); //function prototype for shortest path algorithm
Matrix Warshall(Matrix M);
void main()
{
int i, u;
long D [size+1]; //distance functions
int P [size+1]; //prior vertices in path
cout << "\nLength Matrix: " << L;
cout << "\nPaths that exist:" << Warshall(L);
for (i=1; i <= size; i++) {
D[i] = INFIN; //initialize distance functions
P[i] = 0;
}
cout << "\nFind distance from vertex #";
cin >> begin;
cout << " to vertex #";
cin >> end;
if (begin == end) exit(1);
if (begin < 0 || end < 0) exit(1);
if (begin > size || end > size) exit(1);
path(D,P);
cout << "\nShortest distance from \nvertex #"
<< begin << " to vertex #"
<< end << " is " << D[end];
// u = end;
list<int> stack; // work path backwards
while (1) {
stack.push_front(end);
stack.push_front(begin);
break;
}
cout << "\nusing path:\n";
cout << "\t" << stack.front();
stack.pop_front();
while (stack.size()) {
cout << " -> " << stack.front();
stack.pop_front();
}
getch();
}
void path(long* D, int* P) {
int i, u, dist;
int U[size+1];
for (i=1; i <= size; i++)
U[i] = 0;
U[begin] = 1; // add first vertex;
D[begin] = 0;
u = begin;
do { // until find end vertex
for (i = 1; i <= size; i++) {
dist = L.element(u,i); // distance from u to i
if( D[u] + dist < D[i]) {
D[i] = D[u] + dist;
P[i] = u;
}
}
dist = 38000; // reset distance value to large value
int min;
for(i = 1; i <= size; i++) {
if(L.element(u,i) != 0) {
if(L.element(u,i) < dist && U[i] != 1) {
dist = L.element(u,i);
min = i;
}
}
}
u = min;
U[u] = 1;
cout << "Min is " << min << endl;
} while (u != end);
}
if( D[u] + dist < D[i]) {
D[i] = D[u] + dist;
P[i] = u;
}
should be
if( D[u] + dist < D[i] && dist != 0) {
D[i] = D[u] + dist;
P[i] = u;
}
Related
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);
Kindly help me with the working of Distance transform and rectify the errors. I have tried Borgefors' method which has defined values for Eucledian measure. I get all zeros as output.
Below is the code which i have tried.
int _tmain(int argc, _TCHAR* argv[])
{
Mat v = imread("ref.png", 0);
imshow("input", v);
Mat forward = (Mat_<uchar>(5, 5) << 0, 11, 0, 11, 0, 11, 7, 5, 7, 11, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
Mat backward = (Mat_<uchar>(5, 5) << 0,0,0,0,0, 0,0,0,0,0, 0, 0, 0, 5, 0, 11, 7, 5, 7, 11, 0, 11, 0, 11, 0);
Mat op = cv::Mat::zeros(v.size(), CV_32FC1);
cout << forward;
cout << backward;
int r = v.rows;
int c = v.cols;
float min=100, x = 0;
int size = 3;
int lim = size / 2;
int a, b;
for (int i = lim; i <= r-1-lim; i++)
{
for (int j = lim; j <= c-1-lim; j++)
{
for (int k = -lim; k <= lim; k++)
{
for (int l = -lim; l <= lim; l++)
{
a = (v.at<uchar>(i + k, j + l));
b=(forward.at<uchar>(k + lim, l + lim));
x = a + b;
if (x>0 && min> x)
min = x;
}
}
op.at<float>(i, j) = min;
}
}
cout << min;
for (int i = (r-1-lim); i >lim; i--)
{
for (int j = (c-1-lim); j >lim; j--)
{
for (int k = -lim; k <= lim; k++)
{
for (int l = -lim; l <= lim; l++)
{
a = (v.at<uchar>(i + k, j + l));
b = (forward.at<uchar>(k + lim, l + lim));
x = a + b;
if (x >0 && min> x) min = x;
}
}
op.at<float>(i, j) = min;
}
}
cout << op;
Mat res = cv::Mat::ones(v.size(), CV_8UC1);
normalize(op, res, 0, 255, NORM_MINMAX);
imshow("output",res);
waitKey(0);
return 0;
}
Which is the best method and why it is the best way to implement Distance Transform?
Here is how to fix your code:
Apply the backward mask in the backward loop, you apply the same mask there as in the forward loop.
Use only the defined weights, the values in the mask where you wrote 0 are not part of the mask. Those pixels don't have a distance of 0!
As for your second question, it's probably out of scope for SO. But what the best method is depends very much on the goal. You have a fast and relatively accurate method here, there are other methods that are exact but more expensive.
I am on Ubuntu 16.04, GCC 5.4, latest OpenCV. Suppose I have a vector of double
std::vector<std::vector<double>> vecvecdouble;
vecvecdouble.resize(3, std::vector<double>(3, 0));
for (int j = 0; j < 3; j++){
for (int i = 0; i < 3; i++){
if (i == 0){
vecvecdouble[i][j] = 1;
vecvecdouble[i][j] = 1;
}
if (i == 1){
vecvecdouble[i][j] = 2;
vecvecdouble[i][j] = 2;
}
if (i == 1 && j == 0){
std::cout << vecvecdouble[i - 1][j] << std::endl;
std::cout << vecvecdouble[i][j] << std::endl;
std::cout << vecvecdouble[i + 1][j] << std::endl;
}
}
}
It prints
1
2
0
as expected. However, if I do the same thing with OpenCV cv::mat
std::vector<std::vector<cv::Mat>> vecvecmat;
vecvecmat.resize(
3, std::vector<cv::Mat>(3, cv::Mat(4, 4, CV_64FC1, cv::Scalar(0.0))));
for (int j = 0; j < 3; j++){
for (int i = 0; i < 3; i++){
if (i == 0){
vecvecmat[i][j].at<double>(0, 0) = 1;
vecvecmat[i][j].at<double>(0, 1) = 1;
}
if (i == 1){
vecvecmat[i][j].at<double>(0, 0) = 2;
vecvecmat[i][j].at<double>(0, 1) = 2;
}
if (i == 1 && j == 0){
std::cout << vecvecmat[i - 1][j] << std::endl;
std::cout << vecvecmat[i][j] << std::endl;
std::cout << vecvecmat[i + 1][j] << std::endl;
}
}
}
It prints
[2, 2, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0]
[2, 2, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0]
[2, 2, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0]
which is completely unexpected because I am expecting it to print
[1, 1, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0]
[2, 2, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0]
[0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0;
0, 0, 0, 0]
However, if I don't try to resize the vector in one single line and go through two for loops it actually returns the expected result
std::vector<std::vector<cv::Mat>> vecvecmat;
vecvecmat.resize(3);
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3; j++){
cv::Mat mymat = cv::Mat(4, 4, CV_64FC1, cv::Scalar(0.0));
vecvecmat[i].push_back(mymat);
}
}
for (int j = 0; j < 3; j++){
for (int i = 0; i < 3; i++){
if (i == 0){
vecvecmat[i][j].at<double>(0, 0) = 1;
vecvecmat[i][j].at<double>(0, 1) = 1;
}
if (i == 1){
vecvecmat[i][j].at<double>(0, 0) = 2;
vecvecmat[i][j].at<double>(0, 1) = 2;
}
if (i == 1 && j == 0){
std::cout << vecvecmat[i - 1][j] << std::endl;
std::cout << vecvecmat[i][j] << std::endl;
std::cout << vecvecmat[i + 1][j] << std::endl;
}
}
}
What is wrong with the line?
vecvecmat.resize(3, std::vector<cv::Mat>(3, cv::Mat(4, 4, CV_64FC1, cv::Scalar(0.0))));
The documentation for the copy constructor for cv::Mat says (emphasis mine):
Parameters
m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied by these constructors. Instead, the header pointing to m data or its sub-array is constructed and associated with it. The reference counter, if any, is incremented. So, when you modify the matrix formed using such a constructor, you also modify the corresponding elements of m. If you want to have an independent copy of the sub-array, use Mat::clone().
The initial matrix that you construct in your call to std::vector::resize is being copied into each element of the vector with this copy constructor*, so they are all pointing to the same data. When you modify one matrix, you modify all of them.
* or maybe with operator=, which does the same thing (I'm not sure which, but it doesn't affect the result)
I suggest initializing your vector like this:
std::vector<std::vector<cv::Mat>> vecvecmat;
vecvecmat.resize(3, std::vector<cv::Mat>());
for(auto& v : vecvecmat)
{
for(std::size_t i = 0; i < 3; ++i)
{
v.emplace_back(4, 4, CV_64FC1, cv::Scalar(0.0));
}
}
So this program is supposed to take a string and convert it to Reverse Polish Notation, and then generate the assembly code for it.
For example. If I was to input "x = y", the program would return
"RPN : xy="
"Code:
1 lod y
2 sto x"
However the program instead returns gibberish and continues to do so until it runs out of memory.
Here's the input function
void
getstring()
{
if(datafile) {
file.getline(str,241);
}else{
cout << "Enter a string, please \n\n";
cin.getline( str, 241);
}
nstring++;
}
And these are the functions that work with it.
void
internalize()
{
int i, j;
static char inter[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 6, 4, 0, 5, 0, 7,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0,
0,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27,28,29,30,31,32,33, 0, 0, 0, 0, 0,
0,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
49,50,51,52,53,54,55,56,57,58,59, 0, 0, 0, 0, 0};
char ch, code, k, *p, *q;
cout << "internal form: \n\n";
k=0;
q=inform;
for(p=str;*p;p++){
*q++ = code = inter[(int)*p];
if(k+code == 0){
k = p-str+1;
ch = *p;
}
}
*q = 0;
for(i=j=0, p = inform;p++,j++;j<len){
cout << setw(3) << (int)*p;
if(++i == 16){
cout << '\n';
i = 0;
}
}
if (i !=0){
cout <<'\n';
}
if((err = (0<k))!=0){
cout << '\n**' << (int)k << "-th nonblank char <" <<ch<<"> is illegal. **\n";
}
}
void
makerpn()
{
static char pr[]={0,0,1,2,3,3,4,4};
char n, *p, *r, s, *t;
cout << "\nRPN:\n\n";
t = stak - 1;
r = rpn;
for (p = inform;p++ ; *p){
if(7 < (s = *p)){
*r++ = s;
//a
}else if(s == 1){
*++t = s;
} else{
while(1){
if(t<stak){
*++t = s;
break;
} else if(pr[s] <= pr[n = *t--]){
*r++ = n;
} else if(3 < n+s){
*++t = n;
*++t = s;
}
break;
}
}
while(stak <= t){
*r++ = *t--;
}
*r = '\0';
for(r=rpn;*r;r++){
cout << ext[(int)*r];
}
cout << "\n\n";
}}
void
gencode()
{
void emit(char, char);
char a,j,lop,n1,n2,*p,*t;
cout << "Generated symbolic code \n\n";
j = len = lop = 0;
t = p = rpn;
while(3 <(a = *++p)){
if(7 <a){
*++t = a;
if((++lop == 2) && (0<len)){
n2=*t--;
n1=*t--;
*++t=j+60;
*++t=n1;
*++t=n2;
emit(2,(j++)+60);
}
}else {
if(lop == 1){
emit(a,*t--);
}else{
if( 1 < lop){
n2 = *t--;
n1 = *t--;
emit(1,n1);
emit(a,n2);
}else {
if((a==4) || (a==6)){
n1 = *t--;
emit(a,n1);
}else {
n1=*t--;
emit(2,j+60);
emit(1,n1);
emit(a,j+60);
if( 59 < n1){
--j;}}}}}}
lop = 0;
}
I'm guessing there is something wrong with the loops but I'm not sure what. I've been tweaking them for a while and all I managed to do was to get it to repeat Hp? instead of HW over and over.
for (p = inform;p++ ; *p) will continue until the next value of p is nullptr, and each round will dereference p and discard the result - you probably meant this the other way around.
Similar is this case: for(i=j=0, p = inform;p++,j++;j<len) which will continue running until j++ becomes 0 and discard the result of the comparision j<len each iteration.
In general, there is really only one problem here: Your code is really, really hard to read. Try to break it down into manageable chunks, and verify each one is doing what you want. That way, if there remains a single chunk not doing what you want, you can identify it, and ask for that one specifically instead of dumping a whole program.
I'm trying to implement the merge-sort algorithm. I started with pseudocode that was available in an algorithms book. The pseudocode indicates the first position in the array as 1 and not 0. I am having a very difficult time trying to implement the code.
Here is what I have. I've tried stepping through the recursion by printing out the results at each step but it is very convoluted at this point.
#include <iostream>
#include <deque>
using size_type = std::deque<int>::size_type;
void print(std::deque<int> &v)
{
for(const auto &ref:v)
std::cout << ref << " ";
std::cout << std::endl;
}
void merge(std::deque<int> &vec, size_type p, size_type q, size_type r)
{
int n_1 = q - p;
int n_2 = r - q;
std::deque<int> left, right;
for(auto i = 0; i != n_1; i++)
left.push_back(vec[p + i]);
for(auto j = 0; j != n_2; j++)
right.push_back(vec[q + j]);
int i = 0, j = 0;
std::cout << "left = ";
print(left);
std::cout << "right = ";
print(right);
for(auto k = p; k != r; k++) {
if((i != n_1 && j != n_2) && left[i] <= right[j]) {
vec[k] = left[i];
i++;
}
else if(j != n_2){
vec[k] = right[j];
j++;
}
}
}
void merge_sort(std::deque<int> &A, size_type p, size_type r)
{
int q;
if(p < r - 1) {
q = (p + r)/2;
merge_sort(A, p, q);
merge_sort(A, q + 1, r);
merge(A, p, q, r);
}
}
int main()
{
std::deque<int> small_vec = {1, 6, 2, 10, 5, 2, 12, 6};
std::deque<int> samp_vec = {2, 9, 482, 72, 42, 3, 4, 9, 8, 73, 8, 0, 98, 72, 473, 72, 3, 4, 9, 7, 6, 5, 6953, 583};
print(small_vec);
merge_sort(small_vec, 0, small_vec.size());
print(small_vec);
return 0;
}
I get the following output when I run the program:
left = 1
right = 6
left = 1 6
right = 2 10
left = 2
right = 12 6
left = 1 2 6 10
right = 5 2 12 6
1 2 5 2 6 10 12 6
The error is here: (i != n_1 && j != n_2) && left[i] <= right[j]) when i != n_1 evaluates to false vec[k] = right[j]; is executed - correct.
But if i != n_1 evaluates to true and j != n_2 to false i.e. j = n_2 your program trys to do this vec[k] = right[j]; again i.e. accesing over the bounds of your deque.
Rewrite your for loop as follows:
if (i<n_1 && (j>=n_2 || left[i] <= right[j])
This loop works only due to C++'s short circuiting of the conditions i.e. when j>=n_2 evaluates to true, left[i] <= right[j] is never checked again and you don't access the deque over bounds.
left[i] <= right[j] is being checked only if both i<n_1 is true and j>=n_2 false otherwise the 2nd branch is executed.
After spending a lot of time and getting some valuable help on another post was able to get the algorithm to run correctly.
CORRECT CODE:
#include <iostream>
#include <deque>
using size_type = std::deque<int>::size_type;
void print(std::deque<int> &v)
{
for(const auto &ref:v)
std::cout << ref << " ";
std::cout << std::endl;
}
void print(int arr[], int size)
{
for(int i = 0; i != size; i++)
std::cout << arr[i] << " ";
std::cout << std::endl;
}
void merge(std::deque<int> &vec, size_type p, size_type q, size_type r)
{
int n_1 = q - p + 1;
int n_2 = r - q;
std::deque<int> left, right;
int i = 0, j = 0;
while(i < n_1)
left.push_back(vec[p + i++]);
while(j < n_2)
right.push_back(vec[j++ + q + 1]);
i = 0; j = 0;
//std::cout << "left = ";
//print(left);
//std::cout << "right = ";
//print(right);
for(auto k = p; k <= r; k++) {
if((i < n_1 && left[i] <= right[j]) || j >= n_2) {
vec[k] = left[i++];
}
else if(j < n_2){
vec[k] = right[j++];
}
}
}
void merge_sort(std::deque<int> &A, size_type p, size_type r)
{
int q;
if(p < r) {
q = (r + p) / 2;
std::cout << "q = " << q << std::endl;
//std::cout << "p = " << p << std::endl;
merge_sort(A, p, q);
merge_sort(A, q + 1, r);
merge(A, p, q, r);
}
}
int main()
{
std::deque<int> small_vec = {10, 3, 6, 4, 1, 5, 3, 9, 7, 2, 8};
std::deque<int> samp_vec = {2, 9, 482, 42, 3, 4, 9, 8, 73, 8, 0, 98, 72, 473, 72, 3, 4, 9, 7, 6, 5, 6953, 583};
print(samp_vec);
merge_sort(samp_vec, 0, samp_vec.size() - 1);
print(samp_vec);
return 0;
}