Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use of uninitialized variable in bobyqa altmov_() #36

Closed
gddl opened this issue Apr 27, 2015 · 4 comments
Closed

Use of uninitialized variable in bobyqa altmov_() #36

gddl opened this issue Apr 27, 2015 · 4 comments

Comments

@gddl
Copy link

gddl commented Apr 27, 2015

Under some circumstances the variable ibdsav is used uninitialized.
altmov_() in bobyqa.c

997    if (ibdsav < 0) {
998        xnew[-ibdsav] = sl[-ibdsav];
999    }

The following test code shows the situation that causes lots of NANs in altmov_() and leaves the ibdsav uninitialized. I have no idea, how the correct result for this input should look like - at least it shouldn't segfault. Tested on 64 Bit Linux architectures, gcc 4.8.2.

nlopt-test.cc

/* LN_BOBYQA test causing use of unitialized variable (64 Bit architecture only).
 */

#include <nlopt.hpp>
#include <vector>
#include <limits>
#include <xmmintrin.h>
#include <cstdio>

double callback(const std::vector<double>& x, std::vector<double>& grad, void* data)
{
    return 0.0010540095162719094;
}

int main()
{
    _mm_setcsr(_mm_getcsr() | (_MM_FLUSH_ZERO_ON));

    std::vector<double> lowerBounds(2, 0.0);
    std::vector<double> upperBounds(2, 0.0);
    lowerBounds[0] = -3.1415926535897931;
    lowerBounds[1] = -2.2250738585072014e-307;
    upperBounds[0] = 3.1415926535897931;
    upperBounds[1] = 2.4475812443579215e-307;

    nlopt::opt opt(nlopt::LN_BOBYQA, 2);

    opt.set_lower_bounds(lowerBounds);
    opt.set_upper_bounds(upperBounds);

    opt.set_min_objective(callback, 0);
    opt.set_xtol_rel(1.0e-8);

    double minf;
    std::vector<double> x(2, 0.0);
    x[0] = -0.59243378920273182;
    x[1] = -1.9140531208103923e-307;

    opt.optimize(x, minf);

    return 0;
}
@stevengj
Copy link
Owner

Hmm, digging through the BOBYQA spaghetti code, it seems like if (predsq > presav) on line 975 should be if (predsq >= presav). Can you see if this fixes your problem?

@stevengj
Copy link
Owner

Maybe what is happening here is that BOBYQA doesn't handle the case where the lower and upper bounds are equal. Normally, NLopt checks for this case and eliminates empty dimensions (fixed parameters) before calling BOBYQA. However, because you have set _MM_FLUSH_ZERO_ON, computations involving upperBounds[1] - lowerBounds[1] give zero even though upperBounds[1] != lowerBounds[1] — the latter means that NLopt is passing the dimensions to BOBYQA, but the former means BOBYQA is dividing zero by zero at some point and getting NaNs and other confusion.

@stevengj
Copy link
Owner

Or rather, I think that it may be the default step size that is subnormal in this case.

@stevengj
Copy link
Owner

Should be fixed now, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants