<jupyter_start><jupyter_text>.. _nb_repair:  Repair OperatorThe repair operator is mostly problem dependent. Most commonly it is used to make sure the algorithm is only searching in the feasible space. It is applied after the offsprings have been reproduced. In the following, we are using the knapsack problem to demonstrate the repair operator in *pymoo*. In the well-known **Knapsack Problem**. In this problem, a knapsack has to be filled with items without violating the maximum weight constraint. Each item $j$ has a value $b_j \geq 0$  and a weight $w_j \geq 0$ where $j \in \{1, .., m\}$. The binary decision vector $z = (z_1, .., z_m)$ defines, if an item is picked or not. The aim is to maximize the profit $g(z)$:\begin{eqnarray}max & & g(z) \\[2mm] \notag \text{s.t.} & & \sum_{j=1}^m z_j \, w_j \leq Q \\[1mm] \notag & & z = (z_1, .., z_m) \in \mathbb{B}^m \\[1mm] \notag g(z) & = & \sum_{j=1}^{m}  z_j \, b_j \\[2mm] \notag \end{eqnarray}Because the constraint $\sum_{j=1}^m z_j \, w_j \leq Q$ is fairly easy to satisfy. Therefore, we make sure before evaluating the objective function, that this constraint is not violated.In this framework, a Repair class has to be defined. problem and the population are given as input. The repaired population has to be returned.<jupyter_code>from pymoo.model.repair import Repair

class ConsiderMaximumWeightRepair(Repair):

    def _do(self, problem, pop, **kwargs):
        
        # maximum capacity for the problem
        Q = problem.C
        
        # the packing plan for the whole population (each row one individual)
        Z = pop.get("X")
        
        # the corresponding weight of each individual
        weights = (Z * problem.W).sum(axis=1)
        
        # now repair each indvidiual i
        for i in range(len(Z)):
            
            # the packing plan for i
            z = Z[i]
            
            # while the maximum capacity violation holds
            while weights[i] > Q:
                
                # randomly select an item currently picked
                item_to_remove = random.choice(np.where(z)[0])
                
                # and remove it
                z[item_to_remove] = False
                
                # adjust the weight
                weights[i] -= problem.W[item_to_remove]
          
        # set the design variables for the population
        pop.set("X", Z)
        return pop
import numpy as np

from pymoo.factory import get_algorithm, get_crossover, get_mutation, get_sampling
from pymoo.optimize import minimize
from pymoo.rand import random
from pymop import create_random_knapsack_problem


method = get_algorithm("ga",
                       pop_size=200,
                       sampling=get_sampling("bin_random"),
                       crossover=get_crossover("bin_hux"),
                       mutation=get_mutation("bin_bitflip"),
                       elimate_duplicates=True)

print("\n------------------\nOptimization with no Repair: \n------------------\n")

res = minimize(create_random_knapsack_problem(30),
               method,
               termination=('n_gen', 10),
               disp=True)


print("\n------------------\nOptimization with Repair: \n------------------\n")


method.repair = ConsiderMaximumWeightRepair()


res = minimize(create_random_knapsack_problem(30),
               method,
               termination=('n_gen', 10),
               disp=True)<jupyter_output>------------------
Optimization with no Repair: 
------------------

==================================================
n_gen | n_eval  | cv (min/avg)  | favg  | fopt 
==================================================
1     | 200     | 154.00000 / 505.73500 | -     | -    
2     | 400     | 154.00000 / 363.68000 | -     | -    
3     | 600     | 58.00000 / 275.94000 | -     | -    
4     | 800     | 0.00000 / 197.59500 | -205.00000 | -205.0000000000
5     | 1000    | 0.00000 / 136.85500 | -219.66667 | -293.0000000000
6     | 1200    | 0.00000 / 82.15500 | -281.37500 | -436.0000000000
7     | 1400    | 0.00000 / 38.68000 | -262.23404 | -449.0000000000
8     | 1600    | 0.00000 / 8.63000 | -253.61017 | -449.0000000000
9     | 1800    | 0.00000 / 0.00000 | -262.31500 | -472.0000000000
10    | 2000    | 0.00000 / 0.00000 | -316.07000 | -516.0000000000

------------------
Optimization with Repair: 
------------------

==================================================
n_gen | n_eval  | cv[...]
{'fraction_non_alphanumeric': 0.1641958670260557, 'fraction_numerical': 0.07996406109613657, 'mean_word_length': 1.9805890227576974, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 7, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '653535', 'license': 'Apache-2.0', 'n_tokens_mistral': 1593, 'n_tokens_neox': 1272, 'n_words': 409, 'path': 'doc/source/tutorial/repair.ipynb', 'repo_name': 'temaurer/pymoo', 'size': '4452'}