# Single-Objective with Constraints In this tutorial, we will introduce how to optimize a constrained problem with **OpenBox**. ## Problem Setup First, **define search space** and **define objective function** to **minimize**. Here we use the constrained **Mishra** function. ```python import numpy as np from openbox import space as sp def mishra(config: sp.Configuration): X = np.array([config['x%d' % i] for i in range(2)]) x, y = X[0], X[1] t1 = np.sin(y) * np.exp((1 - np.cos(x))**2) t2 = np.cos(x) * np.exp((1 - np.sin(y))**2) t3 = (x - y)**2 result = dict() result['objectives'] = [t1 + t2 + t3, ] result['constraints'] = [np.sum((X + 5)**2) - 25, ] return result params = { 'float': { 'x0': (-10, 0, -5), 'x1': (-6.5, 0, -3.25) } } space = sp.Space() space.add_variables([ sp.Real(name, *para) for name, para in params['float'].items() ]) ``` After evaluation, the objective function returns a `dict` **(Recommended)**. The result dictionary should contain: + `'objectives'`: A **list/tuple** of **objective values (to be minimized)**. In this example, we have only one objective so the tuple contains a single value. + `'constraints'`: A **list/tuple** of **constraint values**. Non-positive constraint values (**"<=0"**) imply feasibility. ## Optimization After defining the search space and the objective function, we can run the optimization process as follows: ```python from openbox import Optimizer opt = Optimizer( mishra, space, num_constraints=1, num_objectives=1, surrogate_type='gp', # try using 'auto'! acq_optimizer_type='random_scipy', # try using 'auto'! max_runs=50, task_id='soc', # Have a try on the new HTML visualization feature! # visualization='advanced', # or 'basic'. For 'advanced', run 'pip install "openbox[extra]"' first # auto_open_html=True, # open the visualization page in your browser automatically ) history = opt.run() ``` Here we create a `Optimizer` instance, and pass the objective function and the search space to it. The other parameters are: + `num_objectives=1` and `num_constraints=1` indicate that our function returns a single value with one constraint. + `max_runs=50` means the optimization will take 50 rounds (optimizing the objective function 50 times). + `task_id` is set to identify the optimization process. + `visualization`: `'none'`, `'basic'` or `'advanced'`. See {ref}`HTML Visualization `. + `auto_open_html`: whether to open the visualization page in your browser automatically. See {ref}`HTML Visualization `. Then, `opt.run()` is called to start the optimization process. ## Visualization After the optimization, `opt.run()` returns the optimization history. Or you can call `opt.get_history()` to get the history. Then, call `print(history)` to see the result: ```python history = opt.get_history() print(history) ``` ``` +-------------------------+---------------------+ | Parameters | Optimal Value | +-------------------------+---------------------+ | x0 | -3.172421 | | x1 | -1.506397 | +-------------------------+---------------------+ | Optimal Objective Value | -105.72769850551406 | +-------------------------+---------------------+ | Num Configs | 50 | +-------------------------+---------------------+ ``` Call `history.plot_convergence()` to visualize the optimization process: ```python import matplotlib.pyplot as plt history.plot_convergence(true_minimum=-106.7645367) plt.show() ``` (New Feature!) Call `history.visualize_html()` to visualize the optimization process in an HTML page. For `show_importance` and `verify_surrogate`, run `pip install "openbox[extra]"` first. See {ref}`HTML Visualization ` for more details. ```python history.visualize_html(open_html=True, show_importance=True, verify_surrogate=True, optimizer=opt) ```