#! perl

# this code is a fairly close translation of NLopt's test/t_python.py

# /* Copyright (c) 2007-2020 Massachusetts Institute of Technology
#  *                         and other contributors
#  *
#  * Permission is hereby granted, free of charge, to any person obtaining
#  * a copy of this software and associated documentation files (the
#  * "Software"), to deal in the Software without restriction, including
#  * without limitation the rights to use, copy, modify, merge, publish,
#  * distribute, sublicense, and/or sell copies of the Software, and to
#  * permit persons to whom the Software is furnished to do so, subject to
#  * the following conditions:
#  *
#  * The above copyright notice and this permission notice shall be
#  * included in all copies or substantial portions of the Software.
#  *
#  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
#  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
#  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
#  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#  */

use v5.10;
use Test2::V0;
use Math::NLopt 'NLOPT_LD_MMA';
use POSIX 'HUGE_VAL';

sub myfunc {
    my ( $x, $grad ) = @_;

    if ( $grad ) {
        $grad->[0] = 0.0;
        $grad->[1] = 0.5 / sqrt( $x->[1] );
    }
    return sqrt( $x->[1] );
}

sub myconstraint {
    my ( $x, $grad, $aa, $bb ) = @_;

    if ( $grad ) {
        $grad->[0] = 3 * $aa * ( $aa * $x->[0] + $bb )**2;
        $grad->[1] = -1.0;
    }
    return ( $aa * $x->[0] + $bb )**3 - $x->[1];
}

my $opt = Math::NLopt->new( NLOPT_LD_MMA, 2 );

$opt->set_lower_bounds( [ -HUGE_VAL(), 0 ] );
$opt->set_min_objective( \&myfunc );

$opt->add_inequality_constraint(
    sub {
        my ( $x, $grad ) = @_;
        return myconstraint( $x, $grad, 2, 0 );
    },
    tol => 1e-8,
);

$opt->add_inequality_constraint(
    sub {
        my ( $x, $grad ) = @_;
        return myconstraint( $x, $grad, -1, 1 );
    },
    tol => 1e-8,
);
$opt->set_xtol_rel( 1e-4 );
my @x0 = ( 1.234, 5.678 );

is( $opt->optimize( \@x0 ),   [ float( 0.33333333 ), float( 0.29629629 ) ], 'optimum parameters', );
is( $opt->last_optimum_value, float( 0.5443310476200902 ),                  'minimum vlaue', );
is( $opt->last_optimize_result, 4,                                          'result code' );
is( $opt->get_numevals,         11,                                         'nevals' );
is(
    $opt->get_initial_step( \@x0 ),
    array {
        item float( 1.234,  precision => 3 );
        item float( 4.2585, precision => 4 );
    },
    'initial step'
);

done_testing;
