scipy.optimize.minimize(method=’trust-constr’) doesn't terminate on xtol condition

Do you have variables with upper bounds? Perhaps the solver is implementing these as constraints like var < UPPER_BOUND.

(I would put this as a comment if I had the reputation score to do so)


It is linked to an internal conversion of variable boundaries to inequality constraints via the PreparedConstraints class and the initial_constraints_as_canonical function in the function _minimize_trustregion_constr within minimize(method='trust-constr').

The source code, where this is defined can be found in scipy/scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py

The responsible code lines are

if bounds is not None:
    if sparse_jacobian is None:
        sparse_jacobian = True
    prepared_constraints.append(PreparedConstraint(bounds, x0,
                                                   sparse_jacobian))

where the algorithm appends defined variable boundaries bounds as PreparedConstraint to the list of the originally defined constraints already prepared in prepared_constraints. The successing lines

# Concatenate initial constraints to the canonical form.
c_eq0, c_ineq0, J_eq0, J_ineq0 = initial_constraints_as_canonical(
    n_vars, prepared_constraints, sparse_jacobian)

convert each boundary to two inequality constraints (x > lb and x < ub) and returns therefore additional contraints in an amount twice of the number of boundaries.

_minimize_trustregion_constr then detects those unequality constraints and correctly chooses thus the algorithm tr_interior_point

# Choose appropriate method
if canonical.n_ineq == 0:
    method = 'equality_constrained_sqp'
else:
    method = 'tr_interior_point'

In the following, the problem is treated as a problem originally containing inequality constraints and is thus, correctly terminating on the xtol condition AND the barrier_parameter condition as decribed in the question.

Thanks to the hint by @Dylan Black, who is earning the bounty for his answer.