| 454 | typename EXP2 |
| 455 | > |
| 456 | double find_min_box_constrained ( |
| 457 | search_strategy_type search_strategy, |
| 458 | stop_strategy_type stop_strategy, |
| 459 | const funct& f, |
| 460 | const funct_der& der, |
| 461 | T& x, |
| 462 | const matrix_exp<EXP1>& x_lower, |
| 463 | const matrix_exp<EXP2>& x_upper |
| 464 | ) |
| 465 | { |
| 466 | /* |
| 467 | The implementation of this function is more or less based on the discussion in |
| 468 | the paper Projected Newton-type Methods in Machine Learning by Mark Schmidt, et al. |
| 469 | */ |
| 470 | |
| 471 | // make sure the requires clause is not violated |
| 472 | COMPILE_TIME_ASSERT(is_matrix<T>::value); |
| 473 | // The starting point (i.e. x) must be a column vector. |
| 474 | COMPILE_TIME_ASSERT(T::NC <= 1); |
| 475 | |
| 476 | DLIB_CASSERT ( |
| 477 | is_col_vector(x) && is_col_vector(x_lower) && is_col_vector(x_upper) && |
| 478 | x.size() == x_lower.size() && x.size() == x_upper.size(), |
| 479 | "\tdouble find_min_box_constrained()" |
| 480 | << "\n\t The inputs to this function must be equal length column vectors." |
| 481 | << "\n\t is_col_vector(x): " << is_col_vector(x) |
| 482 | << "\n\t is_col_vector(x_upper): " << is_col_vector(x_upper) |
| 483 | << "\n\t is_col_vector(x_upper): " << is_col_vector(x_upper) |
| 484 | << "\n\t x.size(): " << x.size() |
| 485 | << "\n\t x_lower.size(): " << x_lower.size() |
| 486 | << "\n\t x_upper.size(): " << x_upper.size() |
| 487 | ); |
| 488 | DLIB_ASSERT ( |
| 489 | min(x_upper-x_lower) >= 0, |
| 490 | "\tdouble find_min_box_constrained()" |
| 491 | << "\n\t You have to supply proper box constraints to this function." |
| 492 | << "\n\r min(x_upper-x_lower): " << min(x_upper-x_lower) |
| 493 | ); |
| 494 | |
| 495 | |
| 496 | T g, s; |
| 497 | double f_value = f(x); |
| 498 | g = der(x); |
| 499 | |
| 500 | if (!is_finite(f_value)) |
| 501 | throw error("The objective function generated non-finite outputs"); |
| 502 | if (!is_finite(g)) |
| 503 | throw error("The objective function generated non-finite outputs"); |
| 504 | |
| 505 | // gap_eps determines how close we have to get to a bound constraint before we |
| 506 | // start basically dropping it from the optimization and consider it to be an |
| 507 | // active constraint. |
| 508 | const double gap_eps = 1e-8; |
| 509 | |
| 510 | double last_alpha = 1; |
| 511 | while(stop_strategy.should_continue_search(x, f_value, g)) |
| 512 | { |
| 513 | s = search_strategy.get_next_direction(x, f_value, zero_bounded_variables(gap_eps, g, x, g, x_lower, x_upper)); |