| 47 | First we change our Evaluator parameter to be a "User-Defined Evaluator" as shown in the following screenshot. |
| 48 | |
| 49 | [[Image(7-Set-Evaluator.png)]] |
| 50 | |
| 51 | This operator has an !ItemList of operators that are executed one after another on each solution. Let's add a `ProgrammableOperator` from !HeuristicLab.Operators.Programmable to this list and double-click on it so that we get to view it in a new window. |
| 52 | |
| 53 | The parameters tab of our programmable operator is already open. Here we add the parameters that are necessary for performing the evaluation. We need: The `Weights`, the `Values`, the `Size` of the knapsack, the `BinaryVector` solution and a parameter `Quality` which we will return into the scope of the solution. So we add the following parameters: |
| 54 | 1. A `LookupParameter<DoubleArray>` called Weights |
| 55 | 2. A `LookupParameter<DoubleArray>` called Values |
| 56 | 3. A `LookupParameter<DoubleValue>` called Size |
| 57 | 4. A `LookupParameter<BinaryVector>` called !BinaryVector |
| 58 | 5. A `LookupParameter<DoubleValue>` called Quality |
| 59 | |
| 60 | [[Image(8-Evaluator-Parameters.png)]] |
| 61 | |
| 62 | Next we switch to the Code tab and write the evaluation code. Notice that all parameters are available in the method signature. We can write C# code in the text box. Let's write |
| 63 | |
| 64 | {{{#!csharp |
| 65 | DoubleArray weights = Weights.ActualValue; |
| 66 | DoubleArray values = Values.ActualValue; |
| 67 | double size = Size.ActualValue.Value; |
| 68 | BinaryVector solution = BinaryVector.ActualValue; |
| 69 | |
| 70 | double v = 0.0; |
| 71 | double w = 0.0; |
| 72 | for (int i = 0; i < solution.Length; i++) { |
| 73 | if (solution[i]) { |
| 74 | w += weights[i]; |
| 75 | v += values[i]; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | if (w > size) v = 0.0; |
| 80 | |
| 81 | Quality.ActualValue = new DoubleValue(v); |
| 82 | }}} |
| 83 | |
| 84 | In this function we count the values whenever the item in the binary vector is marked for inclusion. We also added a simply penalty in that we set the value to 0 should the knapsack be too heavy and tear. This may not be the best way to handle so called infeasible solutions as it creates a plateau in the fitness landscape which may not direct the optimizer into the feasible region. I'll leave it as an exercise to the reader to think of, define, test and experiment with better penalty functions. |
| 85 | |
| 86 | If we click on the "Compile" button in the upper left we'll notice an error. We need to tell the programmable operator which plugins we want to utilize. It will come preloaded with only a basic set of plugins. We're missing the plugin for !BinaryVector so in the list of assemblies search and select !HeuristicLab.Encodings.!BinaryVectorEncoding and in the namespaces list also check that namespace. Now compilation works and we can close the window of the programmable operator. |
| 87 | |
| 88 | == Optimization == |
| 89 | |
| 90 | Now it's time to review the parameters of our genetic algorithm. For this simple problem I reduced the !PopulationSize to 10, set the !MaximumGenerations to 5 and selected the `SinglePositionBitflipManipulator` as the mutation operator. All other parameters are left unchanged. Save the algorithm and run it. You'll see how it performs in the Results tab. |
| 91 | |
| 92 | [[Image(9-Optimize.png)]] |
| 93 | |
| 94 | You can also download the pre-built file I created in the attachments to this page. |