/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.mahout.ga.watchmaker.travellingsalesman; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.FlowLayout; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.List; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.DefaultListCellRenderer; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; import javax.swing.SpringLayout; import org.uncommons.maths.random.Probability; import org.uncommons.swing.SpringUtilities; import org.uncommons.watchmaker.framework.SelectionStrategy; import org.uncommons.watchmaker.framework.selection.RankSelection; import org.uncommons.watchmaker.framework.selection.RouletteWheelSelection; import org.uncommons.watchmaker.framework.selection.StochasticUniversalSampling; import org.uncommons.watchmaker.framework.selection.TournamentSelection; import org.uncommons.watchmaker.framework.selection.TruncationSelection; /** * Panel for configuring a route-finding strategy for the travelling salesman problem. * * <br> * The original code is from <b>the Watchmaker project</b> (https://watchmaker.dev.java.net/).<br> * The {@code EvolutionPanel} has been modified to add a "distributed (mahout)" JCheckBox. */ final class StrategyPanel extends JPanel { private final DistanceLookup distances; private final JRadioButton evolutionOption; private final JRadioButton bruteForceOption; private final EvolutionPanel evolutionPanel; /** * Creates a panel with components for controlling the route-finding strategy. * * @param distances * Data used by the strategy in order to calculate shortest routes. */ StrategyPanel(DistanceLookup distances) { super(new BorderLayout()); this.distances = distances; evolutionOption = new JRadioButton("Evolution", true); bruteForceOption = new JRadioButton("Brute Force", false); evolutionOption.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent itemEvent) { evolutionPanel.setEnabled(evolutionOption.isSelected()); } }); ButtonGroup strategyGroup = new ButtonGroup(); strategyGroup.add(evolutionOption); strategyGroup.add(bruteForceOption); evolutionPanel = new EvolutionPanel(); add(evolutionOption, BorderLayout.NORTH); add(evolutionPanel, BorderLayout.CENTER); add(bruteForceOption, BorderLayout.SOUTH); setBorder(BorderFactory.createTitledBorder("Route-Finding Strategy")); } public TravellingSalesmanStrategy getStrategy() { return bruteForceOption.isSelected() ? new BruteForceTravellingSalesman(distances) : evolutionPanel.getStrategy(); } @Override public void setEnabled(boolean b) { evolutionOption.setEnabled(b); bruteForceOption.setEnabled(b); evolutionPanel.setEnabled(b && evolutionOption.isSelected()); super.setEnabled(b); } /** * Panel of evolution controls. */ private final class EvolutionPanel extends JPanel { private final JLabel populationLabel; private final JSpinner populationSpinner; private final JLabel elitismLabel; private final JSpinner elitismSpinner; private final JLabel generationsLabel; private final JSpinner generationsSpinner; private final JLabel selectionLabel; private final JComboBox selectionCombo; private final JCheckBox crossoverCheckbox; private final JCheckBox mutationCheckbox; private final JCheckBox distributedCheckbox; EvolutionPanel() { super(new FlowLayout(FlowLayout.LEFT, 0, 0)); Container innerPanel = new JPanel(new SpringLayout()); populationLabel = new JLabel("Population Size: "); populationSpinner = new JSpinner(new SpinnerNumberModel(300, 2, 10000, 1)); populationLabel.setLabelFor(populationSpinner); innerPanel.add(populationLabel); innerPanel.add(populationSpinner); elitismLabel = new JLabel("Elitism: "); elitismSpinner = new JSpinner(new SpinnerNumberModel(3, 0, 10000, 1)); elitismLabel.setLabelFor(elitismSpinner); innerPanel.add(elitismLabel); innerPanel.add(elitismSpinner); generationsLabel = new JLabel("Number of Generations: "); generationsSpinner = new JSpinner(new SpinnerNumberModel(100, 1, 10000, 1)); generationsLabel.setLabelFor(generationsSpinner); innerPanel.add(generationsLabel); innerPanel.add(generationsSpinner); selectionLabel = new JLabel("Selection Strategy: "); innerPanel.add(selectionLabel); SelectionStrategy<?>[] selectionStrategies = {new RankSelection(), new RouletteWheelSelection(), new StochasticUniversalSampling(), new TournamentSelection(new Probability(0.95)), new TruncationSelection(0.5)}; selectionCombo = new JComboBox(selectionStrategies); selectionCombo.setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean hasFocus) { SelectionStrategy<?> strategy = (SelectionStrategy<?>) value; String text = strategy.getClass().getSimpleName(); return super.getListCellRendererComponent(list, text, index, isSelected, hasFocus); } }); selectionCombo.setSelectedIndex(selectionCombo.getItemCount() - 1); innerPanel.add(selectionCombo); crossoverCheckbox = new JCheckBox("Cross-over", true); mutationCheckbox = new JCheckBox("Mutation", true); distributedCheckbox = new JCheckBox("Distributed (Mahout)", false); innerPanel.add(crossoverCheckbox); innerPanel.add(mutationCheckbox); innerPanel.add(distributedCheckbox); innerPanel.add(new JLabel()); // pour avoir un nombre paire de components SpringUtilities.makeCompactGrid(innerPanel, 6, 2, 30, 6, 6, 6); add(innerPanel); } @Override public void setEnabled(boolean b) { populationLabel.setEnabled(b); populationSpinner.setEnabled(b); elitismLabel.setEnabled(b); elitismSpinner.setEnabled(b); generationsLabel.setEnabled(b); generationsSpinner.setEnabled(b); selectionLabel.setEnabled(b); selectionCombo.setEnabled(b); crossoverCheckbox.setEnabled(b); mutationCheckbox.setEnabled(b); distributedCheckbox.setEnabled(b); super.setEnabled(b); } public TravellingSalesmanStrategy getStrategy() { return new EvolutionaryTravellingSalesman(distances, (SelectionStrategy<? super List<String>>) selectionCombo.getSelectedItem(), (Integer) populationSpinner.getValue(), (Integer) elitismSpinner.getValue(), (Integer) generationsSpinner.getValue(), crossoverCheckbox.isSelected(), mutationCheckbox .isSelected(), distributedCheckbox.isSelected()); } } }