Erasing from a vector, passed by reference - c++

I'm attempting to erase elements from a vector, by index, which has been passed by reference to some function. Typically, I'd do so like this:
void erase_element(vector<int> &my_vector, int index){
my_vector.erase(my_vector.begin() + index);
}
void make_vector(){
vector<int> my_vector = {1,2,3,4,5};
erase_element(my_vector, 3);
}
And, indeed, to check my sanity, I ran this and it works.
For some reason, however, this code throws a segfault. The problematic line seems to be that which erases elements from vectors a1, a2, and a3.
My code:
double maximum(double a, double b, double c)
{
return max(max(a, b), c);
}
double minimum(double a, double b, double c)
{
return min(min(a, b), c);
}
void findClosestTriplet(vector<double> &a1, vector<double> &a2, vector<double> &a3, TH2 *histo){
double res_min, res_max, res_mid;
int i = 0, j = 0, k = 0;
int a1Size = a1.size();
int a2Size = a2.size();
int a3Size = a3.size();
double diff = DBL_MAX;
while(i < a1Size && j < a2Size && k < a3Size){
double sum = a1[i] + a2[j] + a3[k];
double min = minimum(a1[i], a2[j], a3[k]);
double max = maximum(a1[i], a2[j], a3[k]);
if(min == a1[i]){
++i;
} else if (min == a2[j]){
++j;
} else {
++k;
}
if (diff > (max-min)){
diff = max - min;
res_max = max;
res_mid = sum - (max + min);
res_min = min;
}
}
a1.erase(a1.begin() + i); a2.erase(a2.begin() + j); a3.erase(a3.begin() + k);
}
void minimizer(){
TH2 *histo = new TH2D("Histo","Histo",1000,-0.1,0.1,1000,-0.1,0.1);
ROOT::RDataFrame f1("D","data1.root");
ROOT::RDataFrame f2("D","data2.root");
ROOT::RDataFrame f3("D","data3.root");
vector<double> a1,a2,a3;
a1.reserve(1E+6); a2.reserve(1E+6); a3.reserve(1E+6);
f1.Foreach([&](double tstamp){a1.push_back(tstamp);},{"UNIX"});
f2.Foreach([&](double tstamp){a2.push_back(tstamp);},{"UNIX"});
f3.Foreach([&](double tstamp){a3.push_back(tstamp);},{"UNIX"});
int maxiter = std::max(std::max(a1.size(), a2.size()), a3.size());
// std::ios_base::sync_with_stdio(false);
// std::cin.tie(NULL);
for(int i = 0; i < maxiter; ++i){
findClosestTriplet(a1,a2,a3,histo);
}
}
I attempted to make a minimal reproducible example, but have failed. This works:
void findClosestTriplet(vector<double> &a1, vector<double> &a2, vector<double> &a3, TH2 *histo){
int i = 1; int j = 2; int k = 3;
a1.erase(a1.begin() + i); a2.erase(a2.begin() + j); a3.erase(a3.begin() + k);
}
void minimizer(){
TH2 *histo = new TH2D("Histo","Histo",1000,-0.1,0.1,1000,-0.1,0.1);
ROOT::RDataFrame f1("D","data1.root");
ROOT::RDataFrame f2("D","data2.root");
ROOT::RDataFrame f3("D","data3.root");
vector<double> a1,a2,a3;
a1.reserve(1E+6); a2.reserve(1E+6); a3.reserve(1E+6);
f1.Foreach([&](double tstamp){a1.push_back(tstamp);},{"UNIX"});
f2.Foreach([&](double tstamp){a2.push_back(tstamp);},{"UNIX"});
f3.Foreach([&](double tstamp){a3.push_back(tstamp);},{"UNIX"});
for(int i = 0; i < a1.size(); ++i){
findClosestTriplet(a1,a2,a3,histo);
std::cout << i << "\n";
}
histo->Draw("colz");
}
Vectors a1,a2, and a3 are identical in both cases. Integers i,j,k are outside of the loop, so that seems unrelated. Moreover, I know that i,j,k are not larger than the size of a1,a2,a3, nor less than 0, at the time of the error.
I know I must be doing something dumb. But what?

One of i, j, or k will be the size of its respective container. The erase call for that element will be equivalent to a.erase(a.begin() + a.size()), or a.erase(a.end()). The iterator passed to erase must be valid and dereferenceable. The end iterator is not derefenceable and cannot be passed to erase.
You must check that the index is in range before using it in your erase call.

Related

How to call ** var in C/C++ 10.5 chapter numerical recipes

I have a problem with calling this function:
void powell(float p[], float **xi, int n,
float ftol, int *iter, float *fret,
float (*func)(float []))
I don't know which argument must be under **xi to run my code.
Whole function below:
void powell(float p[], float** xi, int n, float ftol, int* iter, float* fret, float (*func)(float[]))
{
void linmin(float p[], float xi[], int n, float* fret, float (*func)(float[]));
int i, ibig, j;
float del, fp, fptt, t, *pt, *ptt, *xit;
pt = vector(1, n);
ptt = vector(1, n);
xit = vector(1, n);
*fret = (*func)(p);
for (j = 1; j <= n; j++)
pt[j] = p[j];
for (*iter = 1;; ++(*iter)) {
fp = (*fret);
ibig = 0;
del = 0.0;
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++)
xit[j] = xi[j][i];
fptt = (*fret);
linmin(p, xit, n, fret, func);
if (fptt - (*fret) > del) {
del = fptt - (*fret);
ibig = i;
}
}
if (2.0 * (fp - (*fret)) <= ftol * (fabs(fp) + fabs(*fret)) + TINY) {
free_vector(xit, 1, n);
free_vector(ptt, 1, n);
free_vector(pt, 1, n);
return;
}
if (*iter == ITMAX)
nrerror("powell exceeding maximum iterations.");
for (j = 1; j <= n; j++) {
ptt[j] = 2.0 * p[j] - pt[j];
xit[j] = p[j] - pt[j];
pt[j] = p[j];
}
fptt = (*func)(ptt);
if (fptt < fp) {
t = 2.0 * (fp - 2.0 * (*fret) + fptt) * SQR(fp - (*fret) - del) - del * SQR(fp - fptt);
if (t < 0.0) {
linmin(p, xit, n, fret, func);
for (j = 1; j <= n; j++) {
xi[j][ibig] = xi[j][n];
xi[j][n] = xit[j];
}
}
}
}
}
Thanks in advance.
A double pointer means that the function wants the address of a pointer.
void my_function(int **p_pointer)
{
*p_pointer = new int[42];
}
int main(void)
{
int * pointer = nullptr;
my_function(&pointer);
return 0;
}
In C++, the double pointer can be avoided by using reference:
void another_function(int *& pointer)
{
pointer = new int [256];
}
int main(void)
{
int p = nullptr;
another_function(p);
return 0;
}
One of the primary concerns with pointers is that they can point to anywhere, a defined location or not. Testing a pointer for validity is complex because it depends on the range (or ranges) that are valid for the current platform. With references, the reference is valid, by definition, so no validity checks need to be performed.

C++ simple trick with an array pointer improves performance

I have found a strange behavior in my heap sort routine (see below).
void hpsort(unsigned long n, double *data)
{
unsigned long i, ir, j, l;
double rra;
if (n < 2) return;
l = (n - 2) / 2 + 1;
ir = n - 1;
for (;;)
{
if (l > 0) rra = data[--l];
else
{
rra = data[ir];
data[ir] = data[0];
if (--ir == 0) { data[0] = rra; break; }
}
i = l;
j = l + l + 1;
while (j <= ir)
{
if (j < ir && data[j] < data[j+1]) ++j;
if (rra < data[j])
{
data[i] = data[j];
i = j;
j += j + 1;
}
else break;
}
data[i] = rra;
}
return;
}
If I do a benchmark calling this routine like this
double* array = (double*)malloc(sizeof(double) * N);
... fill in the array ...
hpsort(N, array);
it takes X seconds. but if I add just a single line
void hpsort(unsigned int n, double *data)
{
++data;
and do benchmark as
double* array = (double*)malloc(sizeof(double) * N);
... fill in the array ...
hpsort(N, array-1);
it takes about 0.96X seconds (i.e. 4% faster). This performance difference is stable from run to run.
It feels like g++ compiler does bounds checking in the first case, while in the second case I can cheat it somehow. But I never heard that bounds checking is done for C arrays...
Any ideas why I get this strange difference in performance?
p.s. compilation is done with g++ -O2. by the way, changing unsigned long to long int also decreases performance by about 3 to 4%.
p.p.s. the "Defined Behavior" version also shows performance improvement
void hpsort(unsigned int n, double *data)
{
--data;
and benchmark as
double* array = (double*)malloc(sizeof(double) * N);
... fill in the array ...
hpsort(N, array+1);
p.p.p.s. Performance comparison
Size of array Faster Slower
10 1.46 1.60
100 1.41 1.62
1000 1.84 1.96
10000 1.78 1.87
100000 1.72 1.80
1000000 1.76 1.83
10000000 1.98 2.03
here is my code for hpsort.cpp
void hpsort1(unsigned long n, double *data)
{
unsigned long i, ir, j, l;
double rra;
if (n < 2) return;
l = (n - 2) / 2 + 1;
ir = n - 1;
for (;;)
{
if (l > 0) rra = data[--l];
else
{
rra = data[ir];
data[ir] = data[0];
if (--ir == 0)
{
data[0] = rra;
break;
}
}
i = l;
j = l + l + 1;
while (j <= ir)
{
if (j < ir && data[j] < data[j+1]) ++j;
if (rra < data[j])
{
data[i] = data[j];
i = j;
j += j + 1;
}
else break;
}
data[i] = rra;
}
return;
}
void hpsort2(unsigned long n, double *data)
{
unsigned long i, ir, j, l;
double rra;
--data;
if (n < 2) return;
l = (n - 2) / 2 + 1;
ir = n - 1;
for (;;)
{
if (l > 0) rra = data[--l];
else
{
rra = data[ir];
data[ir] = data[0];
if (--ir == 0)
{
data[0] = rra;
break;
}
}
i = l;
j = l + l + 1;
while (j <= ir)
{
if (j < ir && data[j] < data[j+1]) ++j;
if (rra < data[j])
{
data[i] = data[j];
i = j;
j += j + 1;
}
else break;
}
data[i] = rra;
}
return;
}
and here is my benchmarking code heapsort-benchmark.cpp
#include <vector>
#include <alloca.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
using namespace std;
void hpsort1(unsigned long n, double *data);
void hpsort2(unsigned long n, double *data);
typedef double element_t;
typedef void(*Test)(element_t*, element_t*, int);
const int sizes [] = {10, 100, 1000, 10000, 100000, 1000000, 10000000};
const int largest_size = sizes[sizeof(sizes)/sizeof(int)-1];
vector<double> result_times; // results are pushed into this vector
clock_t start_time;
void do_row(int size) // print results for given size of processed array
{
printf("%10d \t", size);
for (int i=0; i<result_times.size(); ++i) printf("%.2f\t", result_times[i]);
printf("\n");
result_times.clear();
}
inline void start_timer() { start_time = clock(); }
inline double timer()
{
clock_t end_time = clock();
return (end_time - start_time)/double(CLOCKS_PER_SEC);
}
void run(Test f, element_t* first, element_t* last, int number_of_times)
{
start_timer();
while (number_of_times-- > 0) f(first,last,number_of_times);
result_times.push_back(timer());
}
void random_shuffle(double *first, double *last)
{
size_t i, j, n;
double tmp;
n = last-first;
srand((unsigned int)0);
for (i=n-1; i>0; --i)
{
j = rand() % (i+1);
tmp = first[i];
first[i] = first[j];
first[j] = tmp;
}
return;
}
void hpsort1_test(element_t* first, element_t* last, int number_of_times)
{
size_t num_elements = (last-first);
element_t* array = (element_t*)malloc(sizeof(element_t)*num_elements);
memcpy(array, first, sizeof(element_t)*num_elements);
hpsort1(num_elements, array);
free(array);
}
void hpsort2_test(element_t* first, element_t* last, int number_of_times)
{
size_t num_elements = (last-first);
element_t* array = (element_t*)malloc(sizeof(element_t)*num_elements);
memcpy(array, first, sizeof(element_t)*num_elements);
hpsort2(num_elements, array+1);
free(array);
}
void initialize(element_t* first, element_t* last)
{
element_t x = 0.;
while (first != last) { *first++ = x; x += 1.; }
}
double logtwo(double x) { return log(x)/log((double) 2.0); }
int number_of_tests(int size)
{
double n = (double)size;
double largest_n = (double)largest_size;
return int(floor((largest_n * logtwo(largest_n)) / (n * logtwo(n))));
}
void run_tests(int size)
{
const int n = number_of_tests(size);
element_t *buffer = (element_t *)malloc(size * sizeof(element_t));
element_t* buffer_end = &buffer[size];
initialize(buffer, buffer + size); // fill in the elements
for (int i = 0; i < size/2; ++i) buffer[size/2 + i] = buffer[i]; // fill in the second half with values of the first half
//random_shuffle(buffer, buffer_end); // shuffle if you do not want an ordered array
run(hpsort2_test, buffer, buffer_end, n);
run(hpsort1_test, buffer, buffer_end, n);
do_row(size);
free(buffer);
}
int main()
{
const int n = sizeof(sizes)/sizeof(int);
for (int i = 0; i < n; ++i) run_tests(sizes[i]);
}
I compile and run it as
g++ -O2 -c heapsort-benchmark.cpp
g++ -O2 -c hpsort.cpp
g++ -O2 -o heapsort-benchmark heapsort-benchmark.o hpsort.o
./heapsort-benchmark
The first column will be faster version
Unable to get consistent results like OP.
IMO OP's small differences are not part of the difference in code, but part an artifact of testing.
void hpsort(unsigned long n, double *data) {
unsigned long i, ir, j, l;
double rra;
...
}
void hpsort1(unsigned long n, double *data) {
--data;
unsigned long i, ir, j, l;
double rra;
...
}
Test code
#include <time.h>
#include <stdlib.h>
void test(const char *s, int code, size_t n) {
srand(0);
double* array = (double*) malloc(sizeof(double) * n * 2);
// make 2 copies of same random data
for (size_t i = 0; i < n; i++) {
array[i] = rand();
array[i+n] = array[i];
}
double dt0;
double dt1;
clock_t c0 = clock();
clock_t c1,c2;
if (code) {
hpsort1(n, array + 1);
c1 = clock();
hpsort(n, &array[n]);
c2 = clock();
dt0 = (double) (c2 - c1)/CLOCKS_PER_SEC;
dt1 = (double) (c1 - c0)/CLOCKS_PER_SEC;
} else {
hpsort(n, array);
c1 = clock();
hpsort1(n, &array[n]+1);
c2 = clock();
dt0 = (double) (c1 - c0)/CLOCKS_PER_SEC;
dt1 = (double) (c2 - c1)/CLOCKS_PER_SEC;
}
free(array);
const char *cmp = dt0==dt1 ? "==" : (dt0<dt1 ? "<" : ">");
printf("%s %f %2s %f Diff:% f%%\n", s, dt0, cmp, dt1, 100*(dt1-dt0)/dt0);
}
int main() {
//srand((unsigned) time(0));
size_t n = 3000000;
for (int i=0; i<10; i++) {
test("heap first", 0, n);
test("heap1 first", 1, n);
fflush(stdout);
}
}
Output
heap first 1.263000 > 1.201000 Diff:-4.908947%
heap1 first 1.295000 < 1.326000 Diff: 2.393822%
heap first 1.342000 > 1.295000 Diff:-3.502235%
heap1 first 1.279000 < 1.295000 Diff: 1.250977%
heap first 1.279000 == 1.279000 Diff: 0.000000%
heap1 first 1.280000 > 1.279000 Diff:-0.078125%
heap first 1.295000 > 1.294000 Diff:-0.077220%
heap1 first 1.280000 > 1.279000 Diff:-0.078125%
heap first 1.279000 == 1.279000 Diff: 0.000000%
heap1 first 1.295000 > 1.279000 Diff:-1.235521%
heap first 1.263000 < 1.295000 Diff: 2.533650%
heap1 first 1.280000 > 1.279000 Diff:-0.078125%
heap first 1.295000 > 1.263000 Diff:-2.471042%
heap1 first 1.295000 < 1.310000 Diff: 1.158301%
heap first 1.310000 < 1.326000 Diff: 1.221374%
heap1 first 1.326000 < 1.342000 Diff: 1.206637%
heap first 1.279000 == 1.279000 Diff: 0.000000%
heap1 first 1.264000 < 1.295000 Diff: 2.452532%
heap first 1.279000 > 1.264000 Diff:-1.172791%
heap1 first 1.279000 > 1.264000 Diff:-1.172791%

printing the closest pair of points

I was writing this code to find the minimum distance between 2 points.The code I have written gives me the minimum distance correctly but does not give the correct coordinates from which the minimum distance is computed.Kindly help me identify the problem according to me this is the correct approach to print the points as well along with the minimum distance.
#include<bits/stdc++.h>
#define FOR(i,N) for(int i=0;i<(N);i++)
#define rep(i,a,n) for(int i=(a);i<(n);i++)
using namespace std;
struct point {
int x;
int y;
};
typedef struct point point;
void printarr(point arr[], int n) {for(int i = 0; i < n; i++) cout <<
arr[i].x << " " << arr[i].y << endl; cout << endl;
bool comparex(const point& X, const point& Y) { return X.x < Y.x; }
bool comparey(const point& X, const point& Y) { return X.y < Y.y; }
float getdis(point X, point Y) { return sqrt((X.x - Y.x)*(X.x - Y.x) + (X.y
- Y.y)*(X.y - Y.y)); }
float brutedis(point P[], int n, point A[]) {
float d = INT_MAX;
float temp;
FOR(i, n) {
rep(j, i+1, n) {
temp = getdis(P[i],P[j]);
if(temp < d) {
d = temp;
A[0].x = P[i].x; A[0].y = P[i].y;
A[1].x = P[j].x ; A[1].y = P[j].y;
}
}
}
return d;
}
float stripdis(point P[], int n, float d, point A[]) {
float temp = d;
float dis;
sort(P, P + n, comparey);
FOR(i, n) {
rep(j,i+1,n) {
if(abs(P[j].y - P[i].y) < d) {
dis = getdis(P[j], P[i]);
if(dis < temp) {
temp = dis;
A[0].x = P[i].x; A[0].y = P[i].y;
A[1].x = P[j].x ; A[1].y = P[j].y;
}
}
}
}
return temp;
}
float solve(point P[], int n, point A[]) {
if(n <= 3) return brutedis(P, n, A);
int mid = n/2;
point M = P[mid];
float d = min(solve(P, mid, A), solve(P+mid, n-mid, A));
point strip[n];
int j = 0;
int i = 0;
while(i < n) {
if(abs(P[i].x - M.x) < d) strip[j++] = P[i];
i++;
}
return min(d, stripdis(strip, j, d, A));
}
int main() {
point P[] = {{0, 0}, {-4,1}, {-7, -2}, {4, 5}, {1, 1}};
int n = sizeof(P) / sizeof(P[0]);
sort(P, P+n, comparex);
point A[2];
cout << "Minimum Distance = " << solve(P, n, A) << "\n";
printarr(A, 2);
//printarr(P, n);
return 0;
}
To the extent I can follow your badly formatted code, brutedis unconditionally modifies A[] and it gets called again after you have found the right answer (but don't know you found the right answer).
So if the first call were best in min(solve(P, mid, A), solve(P+mid, n-mid, A)); the second could still call brutedis and destroy A[]
You call solve twice, both giving it A as the parameter. Each of these calls always overwrite A, but only one returns the correct answer. And they both call brutedis that also always overwrites A.
The easiest way to fix this is to introduce an additional parameter to all these functions, that would contain the minimal distance found so far, the same way you did with stripdis.
float solve(point P[], int n, float d, point A[]) {
if(n <= 3) return brutedis(P, n, d, A);
...
d = solve(P, mid, d, A);
d = solve(P+mid, n-mid, d, A);
d = stripdis(strip, j, d, A));
...
float brutedis(point P[], int n, float d, point A[])
{
// float d = INT_MAX -- Not needed
Thus A will only be overeritten if the distance between the new pair of points is globally minimal so far.
No need to call min as each function already keeps the minimum of d and the distance it finds.
That is because after getting the correct coordinates in "A" array, you are again updating that. just look for the below statement in your code:
float d = min(solve(P, mid, A), solve(P+mid, n-mid, A));
this will give correct minimum distance but not correct coordinates. Just think about it, if your first call to solve, in the above statement has the minimum distance coordinates, then your second call is going to modify the coordinates in A[]. take a pen and paper and try to solve for the coordinates you have, it'll give you better understanding.

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

C++ implementation of knapsack branch and bound

I am trying to a C++ implementation of this knapsack problem using branch and bounding. There is a Java version on this website here: Implementing branch and bound for knapsack
I'm trying to make my C++ version print out the 90 that it should, however it's not doing that, instead, it's printing out 5.
Does anyone know where and what the problem may be?
#include <queue>
#include <iostream>
using namespace std;
struct node
{
int level;
int profit;
int weight;
int bound;
};
int bound(node u, int n, int W, vector<int> pVa, vector<int> wVa)
{
int j = 0, k = 0;
int totweight = 0;
int result = 0;
if (u.weight >= W)
{
return 0;
}
else
{
result = u.profit;
j = u.level + 1;
totweight = u.weight;
while ((j < n) && (totweight + wVa[j] <= W))
{
totweight = totweight + wVa[j];
result = result + pVa[j];
j++;
}
k = j;
if (k < n)
{
result = result + (W - totweight) * pVa[k]/wVa[k];
}
return result;
}
}
int knapsack(int n, int p[], int w[], int W)
{
queue<node> Q;
node u, v;
vector<int> pV;
vector<int> wV;
Q.empty();
for (int i = 0; i < n; i++)
{
pV.push_back(p[i]);
wV.push_back(w[i]);
}
v.level = -1;
v.profit = 0;
v.weight = 0;
int maxProfit = 0;
//v.bound = bound(v, n, W, pV, wV);
Q.push(v);
while (!Q.empty())
{
v = Q.front();
Q.pop();
if (v.level == -1)
{
u.level = 0;
}
else if (v.level != (n - 1))
{
u.level = v.level + 1;
}
u.weight = v.weight + w[u.level];
u.profit = v.profit + p[u.level];
u.bound = bound(u, n, W, pV, wV);
if (u.weight <= W && u.profit > maxProfit)
{
maxProfit = u.profit;
}
if (u.bound > maxProfit)
{
Q.push(u);
}
u.weight = v.weight;
u.profit = v.profit;
u.bound = bound(u, n, W, pV, wV);
if (u.bound > maxProfit)
{
Q.push(u);
}
}
return maxProfit;
}
int main()
{
int maxProfit;
int n = 4;
int W = 16;
int p[4] = {2, 5, 10, 5};
int w[4] = {40, 30, 50, 10};
cout << knapsack(n, p, w, W) << endl;
system("PAUSE");
}
I think you have put the profit and weight values in the wrong vectors. Change:
int p[4] = {2, 5, 10, 5};
int w[4] = {40, 30, 50, 10};
to:
int w[4] = {2, 5, 10, 5};
int p[4] = {40, 30, 50, 10};
and your program will output 90.
I believe what you are implementing is not a branch & bound algorithm exactly. It is more like an estimation based backtracking if I have to match it with something.
The problem in your algorithm is the data structure that you are using. What you are doing is to simply first push all the first levels, and then to push all second levels, and then to push all third levels to the queue and get them back in their order of insertion. You will get your result but this is simply searching the whole search space.
Instead of poping the elements with their insertion order what you need to do is to branch always on the node which has the highest estimated bound. In other words you are always branching on every node in your way regardless of their estimated bounds. Branch & bound technique gets its speed benefit from branching on only one single node each time which is most probable to lead to the result (has the highest estimated value).
Example : In your first iteration assume that you have found 2 nodes with estimated values
node1: 110
node2: 80
You are pushing them both to your queue. Your queue became "n2-n1-head" In the second iteration you are pushing two more nodes after branching on node1:
node3: 100
node4: 95
and you are adding them to you queue as well("n4-n3-n2-head". There comes the error. In the next iteration what you are going to get will be node2 but instead it should be node3 which has the highest estimated value.
So if I don't miss something in your code both your implementation and the java implementation are wrong. You should rather use a priority queue (heap) to implement a real branch & bound.
You are setting the W to 16, so the result is 5. The only item you can take into the knapsack is item 3 with profit 5 and weight 10.
#include <bits/stdc++.h>
using namespace std;
struct Item
{
float weight;
int value;
};
struct Node
{
int level, profit, bound;
float weight;
};
bool cmp(Item a, Item b)
{
double r1 = (double)a.value / a.weight;
double r2 = (double)b.value / b.weight;
return r1 > r2;
}
int bound(Node u, int n, int W, Item arr[])
{
if (u.weight >= W)
return 0;
int profit_bound = u.profit;
int j = u.level + 1;
int totweight = u.weight;
while ((j < n) && (totweight + arr[j].weight <= W))
{
totweight = totweight + arr[j].weight;
profit_bound = profit_bound + arr[j].value;
j++;
}
if (j < n)
profit_bound = profit_bound + (W - totweight) * arr[j].value /
arr[j].weight;
return profit_bound;
}
int knapsack(int W, Item arr[], int n)
{
sort(arr, arr + n, cmp);
queue<Node> Q;
Node u, v;
u.level = -1;
u.profit = u.weight = 0;
Q.push(u);
int maxProfit = 0;
while (!Q.empty())
{
u = Q.front();
Q.pop();
if (u.level == -1)
v.level = 0;
if (u.level == n-1)
continue;
v.level = u.level + 1;
v.weight = u.weight + arr[v.level].weight;
v.profit = u.profit + arr[v.level].value;
if (v.weight <= W && v.profit > maxProfit)
maxProfit = v.profit;
v.bound = bound(v, n, W, arr);
if (v.bound > maxProfit)
Q.push(v);
v.weight = u.weight;
v.profit = u.profit;
v.bound = bound(v, n, W, arr);
if (v.bound > maxProfit)
Q.push(v);
}
return maxProfit;
}
int main()
{
int W = 55; // Weight of knapsack
Item arr[] = {{10, 60}, {20, 100}, {30, 120}};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "Maximum possible profit = "
<< knapsack(W, arr, n);
return 0;
}
**SEE IF THIS HELPS**