| 285 | |
| 286 | It's a good idea to save the problem so far. You can do that by selecting the tab with the problem, then go to the Edit menu and select "Copy to Clipboard". This will place a clone of that item in the clipboard. So when you continue editing in the current window these changes will not be synced with the clipboard! Thus close the problem tab and open again the problem from the clipboard by double clicking it. That way we are directly modifying the problem in the clipboard. Press the disk icon in the clipboard window (not the one in the toolbar) to save the clipboard to the disk. |
| 287 | |
| 288 | [[Image(Tutorial_SaveToClipboard.png)]] |
| 289 | |
| 290 | The clipboard will be loaded every time the HeuristicLab optimizer is started. It is not saved automatically though, you have to manually save it after making the changes. |
| 291 | |
| 292 | === Configuring the client === |
| 293 | |
| 294 | Finally, the last task is to configure the !EvaluationServiceClient in the problem, but we don't yet have an endpoint for that client. So we should start with the example client from the competition's website. Go to [http://cig.dei.polimi.it/?page_id=103 the competition's website] and download the "Java Client" if you don't have already. Unpack that into a folder and open it using your favorite Java IDE - which is [http://www.eclipse.org/ Eclipse] in my case. Get an overview of the software, it has two packages: evaluator and ga. The !SimpleGA should give us a good overview of what we need to do to communicate to the TORCS driver. Create a new package "heuristiclab" and add a client there to connect our optimization environment. Be sure to include the java service library that you find under attachments and which was described in more detail above. |
| 295 | |
| 296 | Here is the code that I have written using the framework. |
| 297 | |
| 298 | {{{#!java |
| 299 | public class HLEvaluator { |
| 300 | private ServerCommunication simulation; |
| 301 | private double bestQuality; |
| 302 | |
| 303 | public static void main(String[] args) { |
| 304 | HLEvaluator main = new HLEvaluator(); |
| 305 | main.run(); |
| 306 | } |
| 307 | |
| 308 | private void run() { |
| 309 | ServerSocketChannelFactory factory = new ServerSocketChannelFactory(8844); |
| 310 | PollService service = new PollService(factory, 1); |
| 311 | service.start(); |
| 312 | |
| 313 | initializeSimulation(); |
| 314 | bestQuality = Double.MIN_VALUE; |
| 315 | |
| 316 | while (true) { |
| 317 | SolutionMessage solution = service.getSolution(); |
| 318 | |
| 319 | double[] params = getParameters(solution); |
| 320 | int time = getTime(solution); |
| 321 | |
| 322 | try { |
| 323 | Double quality = (Double)simulation.launchSimulation(params, time); |
| 324 | updateBestParams(quality, params); |
| 325 | service.sendQuality(solution, quality); |
| 326 | } catch (Exception e) { |
| 327 | break; |
| 328 | } |
| 329 | } |
| 330 | simulation.close(); |
| 331 | service.stop(); |
| 332 | } |
| 333 | |
| 334 | private double[] getParameters(SolutionMessage solution) { |
| 335 | SolutionMessage.DoubleArrayVariable paramVar = solution.getDoubleArrayVars(0); |
| 336 | List<Double> params = paramVar.getDataList(); |
| 337 | double[] arr = new double[params.size()]; |
| 338 | for (int i = 0; i < arr.length; i++) arr[i] = params.get(i).doubleValue(); |
| 339 | return arr; |
| 340 | } |
| 341 | |
| 342 | private int getTime(SolutionMessage solution) { |
| 343 | SolutionMessage.IntegerVariable timeVar = solution.getIntegerVars(0); |
| 344 | return timeVar.getData(); |
| 345 | } |
| 346 | |
| 347 | private void initializeSimulation() { |
| 348 | simulation = new ServerCommunication("localhost", 3001); |
| 349 | simulation.setFitnessFunction(new Fitness()); |
| 350 | } |
| 351 | |
| 352 | private void updateBestParams(double quality, double[] params) throws Exception { |
| 353 | if (quality > bestQuality) simulation.saveBest(params); |
| 354 | } |
| 355 | |
| 356 | private class Fitness implements FitnessFunction { |
| 357 | public Object getFitness(double bestlap, double topspeed, double distraced, double damage) { |
| 358 | return new Double(distraced); |
| 359 | } |
| 360 | } |
| 361 | } |
| 362 | }}} |
| 363 | |
| 364 | This means that by executing the client we open the port 8844 on this computer and listen for connections to HeuristicLab there. All solution messages are unpacked and the parameters passed on to the simulator. We receive a quality which our client again forwards to HeuristicLab, so it basically sits in between HeuristicLab and the TORCS simulator forwarding the messages and translating them from one format into another. This client will run as long as it receives an exception in which case it stops. That means when the simulator says that enough simulation runs have been performed we cut the connection to HeuristicLab which will again inform the user of an exception and that the algorithm has terminated. This is probably not the most convenient approach, but we are probably eager to get the optimization going and can improve this later on. |
| 365 | |
| 366 | By writing that client we learned that we can also pass the time variable that defines the length of the solution evaluation to the simulator. We don't yet include that in our problem, but since that affects our algorithms and the amount of time they can calculate we should better include this as well. |
| 367 | |
| 368 | ==== Include additional information in the evaluator ==== |
| 369 | |
| 370 | So we go back to our problem, stored in the clipboard. We'll open it from the clipboard and add another parameter to it. It is a !ValueParameter<!IntValue> and we call it "SimulationTime". |
| 371 | |
| 372 | [[Image(Tutorial_AddSimulationTimeParameter.png)]] |
| 373 | |
| 374 | The value of that parameter is null initially so let's assign it a value. Click the pencil icon, confirm the !IntValue and input 600 as value. This is the default setting of the !SimpleGA and probably a good base to start from. We also need to transmit that parameter to the forwarding java client. Open the Evaluator parameter, add a new !LookupParameter<!IntValue> and also call it !SimulationTime. |
| 375 | |
| 376 | ==== Configure the client in the HeuristicLab problem ==== |
| 377 | |
| 378 | Finally visit the Client parameter in our problem, you can see that it has a Channel parameter that is still null. We need to define the channel here. Because our java client listens for connections on a socket will be using an '''!EvaluationTCPChannel'''. Click the Channel, create a new value using the pencil icon and select the TCP channel. Configure the TCP channel according to our java forwarding client. |
| 379 | |
| 380 | [[Image(Tutorial_NewTCPChannel.png)]] |
| 381 | |
| 382 | If you start the java client now and press "Connect" you should be able to establish a connection. Be aware though that the client currently serves just a single connections. So if you disconnect, you have to restart the client. |
| 383 | |
| 384 | === Optimize the problem === |
| 385 | |
| 386 | So now we have the problem configured, we have saved it so that we don't have to do that again, we have written the forwarding client and if the setup with the TORCS simulator was done right we have everything to start optimizing. |
| 387 | |
| 388 | This is so simple it's just a few steps: |
| 389 | 1. Create a GA by selecting File>New and select the "Genetic Algorithm". |
| 390 | 2. Drag the problem from the clipboard into the empty Problem tab (note that this again creates a clone!) |
| 391 | 3. Go to the Parameters tab and configure the GA as you like. Select among the crossovers and manipulators that you have added. Choose the Selection scheme (Proportional, Tournament, Linear Rank,...). Choose the number of Elites, the mutation probability and population size. |
| 392 | 4. Start the TORCS simulator and select the race that you want to evaluate on (look in the manual to see how this is done) |
| 393 | 5. Start the java forwarding client |
| 394 | 6. Click the green arrow button at the bottom of the Genetic Algorithm and watch the optimization run. |