Python termination callback example

import clarabel
import numpy as np
from scipy import sparse


def termination_callback(info: clarabel.DefaultInfo) -> bool:
    """
    Evaluate solver info and return a boolean result.

    Parameters
    ----------
    info : clarabel.DefaultInfo
        The solver info object to evaluate

    Returns
    -------
    bool
        True to signal termination
    """
    if info.iterations < 3:
        print("tick")
        return False  # continue
    else:
        print("BOOM!")
        return True  # stop


P = sparse.csc_matrix([[4., 1.], [1., 2.]])
P = sparse.triu(P).tocsc()

A = sparse.csc_matrix([
    [-1., -1.],
    [-1.,  0.],
    [0.,  -1.],
    [1.,   1.],
    [1.,   0.],
    [0.,   1.]])

q = np.array([1., 1.])
b = np.array([-1., 0., 0., 1., 0.7, 0.7])

cones = [clarabel.NonnegativeConeT(3), clarabel.NonnegativeConeT(3)]
settings = clarabel.DefaultSettings()

# ------------------------------------------------------------
# Solve using a callback
# ------------------------------------------------------------

# solves
solver = clarabel.DefaultSolver(P, q, A, b, cones, settings)
solver.solve()

# stops early
solver.set_termination_callback(termination_callback)
solver.solve()

# works again
solver.unset_termination_callback()
solver.solve()

# ------------------------------------------------------------
# # Solve using a callback with state
# ------------------------------------------------------------

counter = [-1]  # Using a list as a mutable container


def termination_callback_with_state(info: clarabel.DefaultInfo) -> bool:
    # Increment the counter each time the callback is called
    counter[0] += 1
    print(f"Iteration {info.iterations}: Counter = {counter[0]}")

    # Terminate when counter reaches 3
    if counter[0] >= 3:
        return True
    return False


# solves
solver = clarabel.DefaultSolver(P, q, A, b, cones, settings)
solver.solve()

# stops early
solver.set_termination_callback(termination_callback_with_state)
solver.solve()

# works again
solver.unset_termination_callback()
solver.solve()