package uu.mal.skate.view; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.JTextField; import uu.mal.skate.model.Options; import uu.mal.skate.simtype.AdaptiveEpsilonGreedy; import uu.mal.skate.simtype.EpsilonDecreasing; import uu.mal.skate.simtype.EpsilonFirst; import uu.mal.skate.simtype.EpsilonGreedy; import uu.mal.skate.simtype.LinearUpdate; public class OptionsDialog extends JDialog { private static final long serialVersionUID = 1L; public static final int ACTION_CANCEL = 0; public static final int ACTION_START = 1; private final Options options; private int action = ACTION_CANCEL; //private final OptionsField simName; private final OptionsField epsilon; private final OptionsField rewardMove; private final OptionsField rewardCollide; private final OptionsField directionCount; private final OptionsField torusWidth; private final OptionsField torusHeight; private final OptionsField agentCount; private final OptionsField agentCollision; private final OptionsField agentSpeed; private final OptionsField simSpeed; private final OptionsField epsilonFirstN; private final OptionsField epsilonDecrease; private final OptionsField maximumW; private final OptionsField lambda; private final OptionsField alpha; private final OptionsField sigma; private final JComboBox simTypes; private final JCheckBox subtlyImprove; private final JButton btnStart; private final JButton btnCancel; private final JPanel pane = new JPanel(); public OptionsDialog(JFrame frame, Options options) { super(frame, true); if(options == null) options = Options.defaultOptions(); this.options = options; setTitle("New simulation"); //simName = new OptionsField("Simulation name", "", "Unused at the moment"); epsilon = new OptionsField("Epsilon", options.epsilon, "Exploration probability"); rewardMove = new OptionsField("Move reward", options.rewardMove); rewardCollide = new OptionsField("Collision reward", options.rewardCollide); directionCount = new OptionsField("Nr of directions", options.directionCount); torusWidth = new OptionsField("Torus width", options.torusWidth); torusHeight = new OptionsField("Torus height", options.torusHeight); agentCount = new OptionsField("Nr of agents", options.agentCount); agentCollision = new OptionsField("Collision radius", options.agentCollision); agentSpeed = new OptionsField("Agent speed", options.agentSpeed); simSpeed = new OptionsField("Simulation speed", options.simSpeed, "Number of simulation iterations per second."); epsilonFirstN = new OptionsField("Epsilon first N", options.epsilonFirstN, "Explore first N iterations, after this only exploit."); epsilonFirstN.setEnabled(false); epsilonDecrease = new OptionsField("Epsilon decreasing factor (> 0)", options.epsilonDecrease, "Low numbers will cause exploration to quicly drop."); epsilonDecrease.setEnabled(false); maximumW = new OptionsField("Maximum w (>= 0)", options.maximumW, "Random noise will be between 0 and this value.
Set to 0 to disable."); maximumW.setEnabled(false); lambda = new OptionsField("Discount factor [0, 1]", options.lambda); lambda.setEnabled(false); alpha = new OptionsField("Temporal-difference Error modifier (0,1]", options.alpha, "Modifies the difference between the current reward and the learned estimate."); alpha.setEnabled(false); sigma = new OptionsField("Inverse sensitivity (> 0)", options.sigma, "Low inverse sensitivities cause full exploration even at small value changes.
On the other hand, high inverse sensitivities cause a hight level of exploration only at large value changes."); sigma.setEnabled(false); subtlyImprove = new JCheckBox("Subtly improve"); simTypes = new JComboBox<>(new String[] { EpsilonGreedy.class.getSimpleName(), AdaptiveEpsilonGreedy.class.getSimpleName(), EpsilonFirst.class.getSimpleName(), EpsilonDecreasing.class.getSimpleName(), LinearUpdate.class.getSimpleName() }); simTypes.addItemListener(new SimTypeChosenAction()); simTypes.setSelectedItem(options.simType); JPanel simTypePanel = new JPanel(); simTypePanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); simTypePanel.add(new JLabel("Simulation type")); simTypePanel.add(simTypes); JPanel improvePanel = new JPanel(); improvePanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); improvePanel.add(subtlyImprove); btnStart = new JButton("Create"); btnStart.addActionListener(new StartSimAction()); btnCancel = new JButton("Cancel"); btnCancel.addActionListener(new CancelAction()); JPanel btnPanel = new JPanel(); GridBagLayout btnLayout = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; btnPanel.setLayout(btnLayout); c.weightx = 0.5; c.gridx = 0; c.gridy = 0; btnPanel.add(btnCancel, c); c.gridx = 1; c.gridy = 0; btnPanel.add(btnStart, c); BoxLayout l = new BoxLayout(pane, BoxLayout.Y_AXIS); pane.setLayout(l); pane.add(simTypePanel); //pane.add(simName); pane.add(new JSeparator()); pane.add(epsilon); pane.add(epsilonFirstN); pane.add(epsilonDecrease); pane.add(new JSeparator()); pane.add(alpha); pane.add(sigma); pane.add(new JSeparator()); pane.add(lambda); pane.add(maximumW); pane.add(new JSeparator()); pane.add(rewardMove); pane.add(rewardCollide); pane.add(directionCount); pane.add(torusWidth); pane.add(torusHeight); pane.add(agentCount); pane.add(agentCollision); pane.add(agentSpeed); pane.add(simSpeed); pane.add(improvePanel); pane.add(btnPanel); setContentPane(pane); pack(); setVisible(true); } public int getAction() { return action; } public Options getOptions() { options.epsilon = epsilon.getDoubleValue(); options.epsilonFirstN = epsilonFirstN.getIntValue(); options.epsilonDecrease = epsilonDecrease.getDoubleValue(); options.agentCollision = agentCollision.getIntValue(); options.agentCount = agentCount.getIntValue(); options.agentSpeed = agentSpeed.getIntValue(); options.directionCount = directionCount.getIntValue(); options.rewardCollide = rewardCollide.getIntValue(); options.rewardMove = rewardMove.getIntValue(); options.simSpeed = simSpeed.getIntValue(); options.torusHeight = torusHeight.getIntValue(); options.torusWidth = torusWidth.getIntValue(); options.lambda = lambda.getDoubleValue(); options.alpha = alpha.getDoubleValue(); options.sigma = sigma.getDoubleValue(); options.maximumW = maximumW.getDoubleValue(); options.simType = (String) simTypes.getSelectedItem(); options.subtlyImprove = subtlyImprove.isSelected(); options.directions = new double[options.directionCount]; double n = 2 * Math.PI / options.directionCount; for (int i = 0; i < options.directionCount; i++) { options.directions[i] = i * n; } return options; } private class CancelAction implements ActionListener { @Override public void actionPerformed(ActionEvent event) { action = ACTION_CANCEL; OptionsDialog.this.dispose(); } } private class SimTypeChosenAction implements ItemListener { @Override public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == ItemEvent.SELECTED) { String item = (String) event.getItem(); epsilon.setEnabled(item.equals(EpsilonGreedy.class.getSimpleName()) || item.equals(EpsilonFirst.class.getSimpleName())); epsilonFirstN.setEnabled(item.equals(EpsilonFirst.class.getSimpleName())); epsilonDecrease.setEnabled(item.equals(EpsilonDecreasing.class.getSimpleName())); lambda.setEnabled(item.equals(LinearUpdate.class.getSimpleName())); maximumW.setEnabled(item.equals(LinearUpdate.class.getSimpleName())); alpha.setEnabled(item.equals(AdaptiveEpsilonGreedy.class.getSimpleName())); sigma.setEnabled(item.equals(AdaptiveEpsilonGreedy.class.getSimpleName())); if(item.equals(LinearUpdate.class.getSimpleName())) { if(rewardMove.getIntValue() < 0) { rewardMove.setIntValue(0); } if(rewardCollide.getIntValue() < 0) { rewardCollide.setIntValue(0); } } } } } private class StartSimAction implements ActionListener { @Override public void actionPerformed(ActionEvent event) { if(simTypes.getSelectedIndex() >= 0) { action = ACTION_START; OptionsDialog.this.dispose(); } } } private class OptionsField extends JPanel { private static final long serialVersionUID = -2926412308706126069L; private final JTextField txtField; private final JLabel label; public void setEnabled(boolean b) { txtField.setEnabled(b); } public OptionsField(String name, double value, String tooltip) { this(name, Double.toString(value), tooltip); } public OptionsField(String name, double value) { this(name, Double.toString(value)); } public OptionsField(String name, int value, String tooltip) { this(name, Integer.toString(value), tooltip); } public OptionsField(String name, int value) { this(name, Integer.toString(value)); } public double getDoubleValue() { return Double.parseDouble(txtField.getText()); } public int getIntValue() { return Integer.parseInt(txtField.getText()); } @SuppressWarnings("unused") public void setDoubleValue(double value) { this.setValue(Double.toString(value)); } public void setIntValue(int value) { this.setValue(Integer.toString(value)); } public void setValue(String value) { txtField.setText(value); } public OptionsField(String name, String value, String tooltip) { this(name, value); setToolTipText("

" +tooltip+"

"); } public OptionsField(String name, String value) { txtField = new JTextField(value); label = new JLabel(name); txtField.setColumns(12); setLayout(new FlowLayout(FlowLayout.RIGHT)); add(label); add(txtField); } } }