/**
* 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());
}
}
}