|
@@ -0,0 +1,762 @@
|
|
|
+package exampleAlgorithms;
|
|
|
+
|
|
|
+import java.awt.BorderLayout;
|
|
|
+import java.awt.Component;
|
|
|
+import java.awt.Dimension;
|
|
|
+import java.awt.FlowLayout;
|
|
|
+import java.awt.image.BufferedImage;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.text.NumberFormat;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.LinkedList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.ListIterator;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+import javax.swing.BorderFactory;
|
|
|
+import javax.swing.ImageIcon;
|
|
|
+import javax.swing.JButton;
|
|
|
+import javax.swing.JCheckBox;
|
|
|
+import javax.swing.JFormattedTextField;
|
|
|
+import javax.swing.JFrame;
|
|
|
+import javax.swing.JLabel;
|
|
|
+import javax.swing.JOptionPane;
|
|
|
+import javax.swing.JPanel;
|
|
|
+import javax.swing.JProgressBar;
|
|
|
+import javax.swing.JScrollPane;
|
|
|
+import javax.swing.JSplitPane;
|
|
|
+import javax.swing.JTextArea;
|
|
|
+import javax.swing.text.NumberFormatter;
|
|
|
+
|
|
|
+import api.Algorithm;
|
|
|
+import classes.AbstractCpsObject;
|
|
|
+import classes.CpsUpperNode;
|
|
|
+import classes.HolonElement;
|
|
|
+import classes.HolonObject;
|
|
|
+import classes.HolonSwitch;
|
|
|
+import ui.controller.Control;
|
|
|
+import ui.model.DecoratedGroupNode;
|
|
|
+import ui.model.DecoratedState;
|
|
|
+import ui.model.Model;
|
|
|
+import ui.view.Console;
|
|
|
+import ui.model.DecoratedHolonObject.HolonObjectState;
|
|
|
+
|
|
|
+public class AcoAlgorithm implements Algorithm {
|
|
|
+
|
|
|
+ //Parameter for Algo with default Values:
|
|
|
+ /**
|
|
|
+ * Should be even.
|
|
|
+ */
|
|
|
+ private int popsize = 20;
|
|
|
+ private int maxGenerations = 200;
|
|
|
+ /**
|
|
|
+ * The vaporization factor;
|
|
|
+ */
|
|
|
+ private double p = 0.3;
|
|
|
+ private double convergenceFactorReset = 0.99;
|
|
|
+ private int rounds = 3;
|
|
|
+
|
|
|
+ private int resetCount = 0;
|
|
|
+
|
|
|
+
|
|
|
+ //Settings For GroupNode using and cancel
|
|
|
+ private boolean useGroupNode = false;
|
|
|
+ private DecoratedGroupNode dGroupNode = null;
|
|
|
+ private boolean cancel = false;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //Parameter defined by Algo
|
|
|
+ private HashMap<Integer, AccessWrapper> access;
|
|
|
+ LinkedList<List<Boolean>> resetChain = new LinkedList<List<Boolean>>();
|
|
|
+ private List<Boolean> initialState;
|
|
|
+ private List<HolonSwitch> switchList;
|
|
|
+ private List<HolonObject> objectList;
|
|
|
+
|
|
|
+ //Gui Part:
|
|
|
+ private Control control;
|
|
|
+ private Console console = new Console();
|
|
|
+ private JPanel content = new JPanel();
|
|
|
+ //ProgressBar
|
|
|
+ private JProgressBar progressBar = new JProgressBar();
|
|
|
+ private int progressBarCount = 0;
|
|
|
+ private long startTime;
|
|
|
+ private Thread runThread;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public static void main(String[] args)
|
|
|
+ {
|
|
|
+ JFrame newFrame = new JFrame("exampleWindow");
|
|
|
+ AcoAlgorithm instance = new AcoAlgorithm();
|
|
|
+ newFrame.setContentPane(instance.getAlgorithmPanel());
|
|
|
+ newFrame.pack();
|
|
|
+ newFrame.setVisible(true);
|
|
|
+ newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
|
|
+ }
|
|
|
+ public AcoAlgorithm() {
|
|
|
+ content.setLayout(new BorderLayout());
|
|
|
+ JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
|
|
|
+ createOptionPanel() , console);
|
|
|
+ splitPane.setResizeWeight(0.0);
|
|
|
+ content.add(splitPane, BorderLayout.CENTER);
|
|
|
+ content.setPreferredSize(new Dimension(800,800));
|
|
|
+ }
|
|
|
+ public JPanel createOptionPanel() {
|
|
|
+ JPanel optionPanel = new JPanel(new BorderLayout());
|
|
|
+ JScrollPane scrollPane = new JScrollPane(createParameterPanel());
|
|
|
+ scrollPane.setBorder(BorderFactory.createTitledBorder("Parameter"));
|
|
|
+ optionPanel.add(scrollPane, BorderLayout.CENTER);
|
|
|
+ optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
|
|
|
+ return optionPanel;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Component createParameterPanel() {
|
|
|
+ JPanel parameterPanel = new JPanel(null);
|
|
|
+ parameterPanel.setPreferredSize(new Dimension(510,300));
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ JLabel maxGenerationsLabel = new JLabel("Max. Generations:");
|
|
|
+ maxGenerationsLabel.setBounds(20, 60, 150, 20);
|
|
|
+ parameterPanel.add(maxGenerationsLabel);
|
|
|
+
|
|
|
+ JLabel populationLabel = new JLabel("Population Size:");
|
|
|
+ populationLabel.setBounds(20, 85, 150, 20);
|
|
|
+ parameterPanel.add(populationLabel);
|
|
|
+
|
|
|
+ JLabel roundLabel = new JLabel("Rounds:");
|
|
|
+ roundLabel.setBounds(20, 110, 150, 20);
|
|
|
+ parameterPanel.add(roundLabel);
|
|
|
+
|
|
|
+ JLabel vaporizationLabel = new JLabel("Vaporization:");
|
|
|
+ vaporizationLabel.setBounds(20, 135, 150, 20);
|
|
|
+ parameterPanel.add(vaporizationLabel);
|
|
|
+
|
|
|
+
|
|
|
+ JLabel resetLabel = new JLabel("Reset Trigger:");
|
|
|
+ resetLabel.setBounds(20, 160, 150, 20);
|
|
|
+ parameterPanel.add(resetLabel);
|
|
|
+
|
|
|
+
|
|
|
+ JLabel progressLabel = new JLabel("Progress:");
|
|
|
+ progressLabel.setBounds(350, 135, 170, 20);
|
|
|
+ parameterPanel.add(progressLabel);
|
|
|
+
|
|
|
+ progressBar.setBounds(350, 155, 185, 20);
|
|
|
+ progressBar.setStringPainted(true);
|
|
|
+ parameterPanel.add(progressBar);
|
|
|
+
|
|
|
+ JPanel borderPanel = new JPanel(null);
|
|
|
+ borderPanel.setBounds(350, 85, 185, 50);
|
|
|
+ borderPanel.setBorder(BorderFactory.createTitledBorder(""));
|
|
|
+ parameterPanel.add(borderPanel);
|
|
|
+
|
|
|
+ JLabel showGroupNodeLabel = new JLabel("Use Group Node:");
|
|
|
+ showGroupNodeLabel.setBounds(10, 1, 170, 20);
|
|
|
+ borderPanel.add(showGroupNodeLabel);
|
|
|
+
|
|
|
+ JButton selectGroupNodeButton = new JButton("Select GroupNode");
|
|
|
+ selectGroupNodeButton.setEnabled(false);
|
|
|
+ selectGroupNodeButton.setBounds(10, 25, 165, 20);
|
|
|
+ selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode());
|
|
|
+ borderPanel.add(selectGroupNodeButton);
|
|
|
+
|
|
|
+ JCheckBox useGroupNodeCheckBox = new JCheckBox();
|
|
|
+ useGroupNodeCheckBox.setSelected(false);
|
|
|
+ useGroupNodeCheckBox.setBounds(155, 1, 25, 20);
|
|
|
+ useGroupNodeCheckBox.addActionListener(actionEvent -> {
|
|
|
+ useGroupNode = useGroupNodeCheckBox.isSelected();
|
|
|
+ selectGroupNodeButton.setEnabled(useGroupNode);
|
|
|
+ });
|
|
|
+ borderPanel.add(useGroupNodeCheckBox);
|
|
|
+
|
|
|
+
|
|
|
+ //Integer formatter
|
|
|
+ NumberFormat format = NumberFormat.getIntegerInstance();
|
|
|
+ format.setGroupingUsed(false);
|
|
|
+ format.setParseIntegerOnly(true);
|
|
|
+ NumberFormatter integerFormatter = new NumberFormatter(format);
|
|
|
+ integerFormatter.setMinimum(1);
|
|
|
+ integerFormatter.setCommitsOnValidEdit(true);
|
|
|
+
|
|
|
+
|
|
|
+ JFormattedTextField maxGenerationsTextField = new JFormattedTextField(integerFormatter);
|
|
|
+ maxGenerationsTextField.setValue(this.maxGenerations);
|
|
|
+ maxGenerationsTextField.setToolTipText("Only positive Integer.");
|
|
|
+ maxGenerationsTextField.addPropertyChangeListener(actionEvent -> this.maxGenerations = Integer.parseInt(maxGenerationsTextField.getValue().toString()));
|
|
|
+ maxGenerationsTextField.setBounds(160, 60, 50, 20);
|
|
|
+ parameterPanel.add(maxGenerationsTextField);
|
|
|
+
|
|
|
+ JFormattedTextField popSizeTextField = new JFormattedTextField(integerFormatter);
|
|
|
+ popSizeTextField.setValue(this.popsize);
|
|
|
+ popSizeTextField.setToolTipText("Only positive Integer.");
|
|
|
+ popSizeTextField.addPropertyChangeListener(propertyChange -> this.popsize = Integer.parseInt(popSizeTextField.getValue().toString()));
|
|
|
+ popSizeTextField.setBounds(160, 85, 50, 20);
|
|
|
+ parameterPanel.add(popSizeTextField);
|
|
|
+
|
|
|
+
|
|
|
+ JFormattedTextField roundsTextField = new JFormattedTextField(integerFormatter);
|
|
|
+ roundsTextField.setValue(this.rounds);
|
|
|
+ roundsTextField.setToolTipText("Only positive Integer.");
|
|
|
+ roundsTextField.addPropertyChangeListener(propertyChange -> this.rounds = Integer.parseInt(roundsTextField.getValue().toString()));
|
|
|
+ roundsTextField.setBounds(160, 110, 50, 20);
|
|
|
+ parameterPanel.add(roundsTextField);
|
|
|
+
|
|
|
+
|
|
|
+ //Double Format:
|
|
|
+ NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US);
|
|
|
+ doubleFormat.setMinimumFractionDigits(1);
|
|
|
+ doubleFormat.setMaximumFractionDigits(3);
|
|
|
+ doubleFormat.setRoundingMode(RoundingMode.HALF_UP);
|
|
|
+
|
|
|
+ //Limit Formatter:
|
|
|
+ NumberFormatter limitFormatter = new NumberFormatter(doubleFormat);
|
|
|
+ limitFormatter.setMinimum(0.0);
|
|
|
+ limitFormatter.setMaximum(1.0);
|
|
|
+
|
|
|
+ JFormattedTextField vaporizationField = new JFormattedTextField(limitFormatter);
|
|
|
+ vaporizationField.setValue(this.p);
|
|
|
+ vaporizationField.setToolTipText("Only Double in range [0.0, 1.0] with DecimalSeperator Point('.').");
|
|
|
+ vaporizationField.addPropertyChangeListener(propertyChange -> p = Double.parseDouble(vaporizationField.getValue().toString()));
|
|
|
+ vaporizationField.setBounds(160, 135, 50, 20);
|
|
|
+ parameterPanel.add(vaporizationField);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ JFormattedTextField resetFactorField = new JFormattedTextField(limitFormatter);
|
|
|
+ resetFactorField.setValue(this.convergenceFactorReset);
|
|
|
+ resetFactorField.setToolTipText("Only Double in range [0.0, 1.0] with DecimalSeperator Point('.').");
|
|
|
+ resetFactorField.addPropertyChangeListener(propertyChange -> this.convergenceFactorReset = Double.parseDouble(resetFactorField.getValue().toString()));
|
|
|
+ resetFactorField.setBounds(160, 160, 50, 20);
|
|
|
+ parameterPanel.add(resetFactorField);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return parameterPanel;
|
|
|
+ }
|
|
|
+ public JPanel createButtonPanel() {
|
|
|
+ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
|
|
+ JButton resetButton = new JButton("ResetAll");
|
|
|
+ resetButton.setToolTipText("Resets the State to before the Algorithm has runed.");
|
|
|
+ resetButton.addActionListener(actionEvent -> resetAll());
|
|
|
+ buttonPanel.add(resetButton);
|
|
|
+ JButton cancelButton = new JButton("Cancel Run");
|
|
|
+ cancelButton.addActionListener(actionEvent -> cancel());
|
|
|
+ buttonPanel.add(cancelButton);
|
|
|
+ JButton undoButton = new JButton("Undo");
|
|
|
+ undoButton.setToolTipText("One Algo Step Back.");
|
|
|
+ undoButton.addActionListener(actionEvent -> resetLast());
|
|
|
+ buttonPanel.add(undoButton);
|
|
|
+ JButton runButton = new JButton("Run");
|
|
|
+ runButton.addActionListener(actionEvent -> {
|
|
|
+ Runnable task = () -> run();
|
|
|
+ runThread = new Thread(task);
|
|
|
+ runThread.start();
|
|
|
+ });
|
|
|
+ buttonPanel.add(runButton);
|
|
|
+ return buttonPanel;
|
|
|
+ }
|
|
|
+ private void cancel() {
|
|
|
+ if(runThread.isAlive()) {
|
|
|
+ println("");
|
|
|
+ println("Cancel run.");
|
|
|
+ cancel = true;
|
|
|
+ progressBar.setValue(0);
|
|
|
+ } else {
|
|
|
+ println("Nothing to cancel.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void run() {
|
|
|
+ cancel = false;
|
|
|
+ disableGuiInput(true);
|
|
|
+ executeAlgoWithParameter();
|
|
|
+ updateVisual();
|
|
|
+ disableGuiInput(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void resetLast() {
|
|
|
+ if(runThread.isAlive()) {
|
|
|
+ println("Run have to be cancelled First.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(!resetChain.isEmpty()) {
|
|
|
+ println("Resetting..");
|
|
|
+ resetState();
|
|
|
+ resetChain.removeLast();
|
|
|
+ control.resetSimulation();
|
|
|
+ updateVisual();
|
|
|
+ }else {
|
|
|
+ println("No run inistialized.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void resetAll() {
|
|
|
+ if(runThread.isAlive()) {
|
|
|
+ println("Run have to be cancelled First.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(!resetChain.isEmpty()) {
|
|
|
+ println("Resetting..");
|
|
|
+ setState(resetChain.getFirst());
|
|
|
+ resetChain.clear();
|
|
|
+ control.resetSimulation();
|
|
|
+ control.setCurIteration(0);
|
|
|
+ updateVisual();
|
|
|
+ }else {
|
|
|
+ println("No run inistialized.");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ private void disableGuiInput(boolean bool) {
|
|
|
+ control.guiDiable(bool);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public JPanel getAlgorithmPanel() {
|
|
|
+ return content;
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void setController(Control control) {
|
|
|
+ this.control = control;
|
|
|
+
|
|
|
+ }
|
|
|
+ private void println(String message) {
|
|
|
+ console.println(message);
|
|
|
+ }
|
|
|
+ private void selectGroupNode() {
|
|
|
+ Object[] possibilities = control.getSimManager().getActualVisualRepresentationalState().getCreatedGroupNodes().values().stream().map(aCps -> new Handle<DecoratedGroupNode>(aCps)).toArray();
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ Handle<DecoratedGroupNode> selected = (Handle<DecoratedGroupNode>) JOptionPane.showInputDialog(content, "Select GroupNode:", "GroupNode?", JOptionPane.OK_OPTION,new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)) , possibilities, "");
|
|
|
+ if(selected != null) {
|
|
|
+ println("Selected: " + selected);
|
|
|
+ dGroupNode = selected.object;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private void progressBarStep(){
|
|
|
+ progressBar.setValue(++progressBarCount);
|
|
|
+ }
|
|
|
+ private void calculateProgressBarParameter() {
|
|
|
+ int max = this.maxGenerations * this.popsize * this.rounds;
|
|
|
+ progressBarCount = 0;
|
|
|
+ progressBar.setValue(0);
|
|
|
+ progressBar.setMaximum(max);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void startTimer(){
|
|
|
+ startTime = System.currentTimeMillis();
|
|
|
+ }
|
|
|
+ private void printElapsedTime(){
|
|
|
+ long elapsedMilliSeconds = System.currentTimeMillis() - startTime;
|
|
|
+ println("Execution Time of Algo in Milliseconds:" + elapsedMilliSeconds);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ private void executeAlgoWithParameter(){
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ int actualIteration = control.getModel().getCurIteration();
|
|
|
+ println("TimeStep:" + actualIteration);
|
|
|
+ calculateProgressBarParameter();
|
|
|
+ println("Algo Parameter: p="+ p + " cfreset=" + convergenceFactorReset);
|
|
|
+ resetCount = 0;
|
|
|
+ startTimer();
|
|
|
+ Individual runBest = new Individual();
|
|
|
+ runBest.fitness = Double.MAX_VALUE;
|
|
|
+ for(int r = 0; r < rounds; r++)
|
|
|
+ {
|
|
|
+ Individual roundBest = executeAcoAlgo();
|
|
|
+ if(cancel)return;
|
|
|
+ resetState();
|
|
|
+ if(roundBest.fitness < runBest.fitness) runBest = roundBest;
|
|
|
+ }
|
|
|
+ printElapsedTime();
|
|
|
+ setState(runBest.position);
|
|
|
+ updateVisual();
|
|
|
+ println("ResetsCount:"+resetCount);
|
|
|
+ println("AlgoResult:" + runBest.fitness);
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //Algo Part:
|
|
|
+ /**
|
|
|
+ * Algorithm 20 !! Fitness is better when smaller.:
|
|
|
+ * PseudoCode:
|
|
|
+ * Best <- actual;
|
|
|
+ * pheromones = initPheromons();
|
|
|
+ * for(maxGeneration times){
|
|
|
+ * population = createSolutionsBiasedBy(pheromones);
|
|
|
+ * for(each Individual i from population){
|
|
|
+ * fitness <- evaluatePosition(i);
|
|
|
+ * if(fitness < best.fitnessValue) Best <- i;
|
|
|
+ * }
|
|
|
+ * vaporizeIntensifiePheromons(pheromones);
|
|
|
+ * }
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Individual executeAcoAlgo() {
|
|
|
+ Individual best = new Individual();
|
|
|
+ best.position = extractPositionAndAccess();
|
|
|
+ println("Bit-Array_length: " + best.position.size());
|
|
|
+ best.fitness = evaluatePosition(best.position, false);
|
|
|
+ println("Start with Fitness: " + best.fitness);
|
|
|
+ int problemSize = best.position.size();
|
|
|
+ if(problemSize == 0) return best;
|
|
|
+ List<Double> pheromones = initPheromones(problemSize);
|
|
|
+ List<Individual> population = new ArrayList<Individual>();
|
|
|
+ println("Size To Test:" + population.size());
|
|
|
+ for(int generation = 0; generation< maxGenerations; generation++) {
|
|
|
+ population.clear();
|
|
|
+ population = constructSolutionsBiasedBy(pheromones);
|
|
|
+ println("Generation" + generation + " start with Fitness: " + best.fitness);
|
|
|
+ for(Individual i : population) {
|
|
|
+ i.fitness = evaluatePosition(i.position, true);
|
|
|
+ println("Fitness" + i.fitness);
|
|
|
+ if(i.fitness < best.fitness) best = i;
|
|
|
+ }
|
|
|
+ println("________________");
|
|
|
+ vaporizeIntensifiePheromons(pheromones, best.position, problemSize);
|
|
|
+ double cf = calculateConvergenceFactor(pheromones, problemSize);
|
|
|
+ println("ConvergenceFactor = " + cf);
|
|
|
+ if(cf > this.convergenceFactorReset) {
|
|
|
+ pheromones = initPheromones(problemSize);
|
|
|
+ resetCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ println("RoundResult:" + best.fitness);
|
|
|
+ return best;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * tj1 is the pheromon level in the j position
|
|
|
+ * cf is the convergence factor cf e [0;1]
|
|
|
+ * difference = | tj1 - tj0 | = | tj1 - (1 - tj1) |
|
|
|
+ *
|
|
|
+ *
|
|
|
+ *
|
|
|
+ * @param pheromones
|
|
|
+ * @return cf
|
|
|
+ */
|
|
|
+ private double calculateConvergenceFactor(List<Double> pheromones,int problemSize) {
|
|
|
+ double sumOfDifference = pheromones.stream().map(tj1 -> Math.abs(tj1 - (1.0 - tj1))).reduce(0.0, Double::sum);
|
|
|
+ double cf = sumOfDifference / (double)problemSize;
|
|
|
+ return cf;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * pheromone <- (1-p) * pheromone;
|
|
|
+ * if(best is true at this position) pheromone <- pheromone + p;
|
|
|
+ * @param pheromones
|
|
|
+ * @param position
|
|
|
+ */
|
|
|
+ private void vaporizeIntensifiePheromons(List<Double> pheromones, List<Boolean> position, int problemSize) {
|
|
|
+ ListIterator<Double> iterPheromone = pheromones.listIterator();
|
|
|
+ ListIterator<Boolean> iterBest = position.listIterator();
|
|
|
+ for(int i = 0; i < problemSize; i++) {
|
|
|
+ double pheromone = iterPheromone.next();
|
|
|
+ boolean bestDecision = iterBest.next();
|
|
|
+ iterPheromone.set((1.0 - p) * pheromone + (bestDecision?p:0.0));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param pheromones
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<Individual> constructSolutionsBiasedBy(List<Double> pheromones) {
|
|
|
+ List<Individual> population = new ArrayList<Individual>();
|
|
|
+ for(int i = 0; i < popsize; i++) {
|
|
|
+ population.add(constructASolutionBiasedBy(pheromones));
|
|
|
+ }
|
|
|
+ return population;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Walks the path with a ant and decide by pheromones if should take true or false;
|
|
|
+ * A pheromone have a level of 0 < pheromone < 1.
|
|
|
+ * A Pheromone is equal to the probability.
|
|
|
+ * @param pheromones
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Individual constructASolutionBiasedBy(List<Double> pheromones) {
|
|
|
+ Individual result = new Individual();
|
|
|
+ result.position = new ArrayList<Boolean>();
|
|
|
+ for(double pheromone : pheromones) {
|
|
|
+ result.position.add((Random.nextDouble() < pheromone));
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Initialize Pheromons with 0.5
|
|
|
+ */
|
|
|
+ private List<Double> initPheromones(int problemSize) {
|
|
|
+ List<Double> result = new ArrayList<Double>();
|
|
|
+ for(int i = 0; i < problemSize;i++) {
|
|
|
+ result.add(0.5);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Method to get the current Position alias a ListOf Booleans for aktive settings on the Objects on the Canvas.
|
|
|
+ * Also initialize the Access Hashmap to swap faster positions.
|
|
|
+ * @param model
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<Boolean> extractPositionAndAccess() {
|
|
|
+ Model model = control.getModel();
|
|
|
+ switchList = new ArrayList<HolonSwitch>();
|
|
|
+ objectList = new ArrayList<HolonObject>();
|
|
|
+ initialState = new ArrayList<Boolean>();
|
|
|
+ access= new HashMap<Integer, AccessWrapper>();
|
|
|
+ rollOutNodes((useGroupNode && (dGroupNode != null))? dGroupNode.getModel().getNodes() :model.getObjectsOnCanvas(), initialState, model.getCurIteration());
|
|
|
+ resetChain.add(initialState);
|
|
|
+ return initialState;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Method to extract the Informations recursively out of the Model.
|
|
|
+ * @param nodes
|
|
|
+ * @param positionToInit
|
|
|
+ * @param timeStep
|
|
|
+ */
|
|
|
+ private void rollOutNodes(List<AbstractCpsObject> nodes, List<Boolean> positionToInit, int timeStep) {
|
|
|
+ for(AbstractCpsObject aCps : nodes) {
|
|
|
+ if (aCps instanceof HolonObject) {
|
|
|
+ for (HolonElement hE : ((HolonObject) aCps).getElements()) {
|
|
|
+ positionToInit.add(hE.isActive());
|
|
|
+ access.put(positionToInit.size() - 1 , new AccessWrapper(hE));
|
|
|
+ }
|
|
|
+ objectList.add((HolonObject) aCps);
|
|
|
+ }
|
|
|
+ else if (aCps instanceof HolonSwitch) {
|
|
|
+ HolonSwitch sw = (HolonSwitch) aCps;
|
|
|
+ positionToInit.add(sw.getState(timeStep));
|
|
|
+ switchList.add(sw);
|
|
|
+ access.put(positionToInit.size() - 1 , new AccessWrapper(sw));
|
|
|
+ }
|
|
|
+ else if(aCps instanceof CpsUpperNode) {
|
|
|
+ rollOutNodes(((CpsUpperNode)aCps).getNodes(), positionToInit ,timeStep );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ private double evaluatePosition(List<Boolean> position, boolean doIncreaseCounter) {
|
|
|
+ setState(position);
|
|
|
+ if(doIncreaseCounter)progressBarStep();
|
|
|
+ control.calculateStateOnlyForCurrentTimeStep();
|
|
|
+ DecoratedState actualstate = control.getSimManager().getActualDecorState();
|
|
|
+ return PSOAlgorithm.getFitnessValueForState(actualstate);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * To let the User See the current state without touching the Canvas.
|
|
|
+ */
|
|
|
+ private void updateVisual() {
|
|
|
+ control.calculateStateAndVisualForCurrentTimeStep();
|
|
|
+ //control.updateCanvas();
|
|
|
+ //control.getGui().triggerUpdateController(null);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Sets the Model back to its original State before the LAST run.
|
|
|
+ */
|
|
|
+ private void resetState() {
|
|
|
+ setState(resetChain.getLast());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sets the State out of the given position for calculation or to show the user.
|
|
|
+ * @param position
|
|
|
+ */
|
|
|
+ private void setState(List<Boolean> position) {
|
|
|
+ for(int i = 0;i<position.size();i++) {
|
|
|
+ access.get(i).setState(position.get(i));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private class Individual {
|
|
|
+ public double fitness;
|
|
|
+ public List<Boolean> position;
|
|
|
+
|
|
|
+ Individual(){};
|
|
|
+ /**
|
|
|
+ * Copy Constructor
|
|
|
+ */
|
|
|
+ Individual(Individual c){
|
|
|
+ position = c.position.stream().collect(Collectors.toList());
|
|
|
+ fitness = c.fitness;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split the List.
|
|
|
+ */
|
|
|
+ private class AccessWrapper {
|
|
|
+ public static final int HOLONELEMENT = 0;
|
|
|
+ public static final int SWITCH = 1;
|
|
|
+ private int type;
|
|
|
+ private HolonSwitch hSwitch;
|
|
|
+ private HolonElement hElement;
|
|
|
+ public AccessWrapper(HolonSwitch hSwitch){
|
|
|
+ type = SWITCH;
|
|
|
+ this.hSwitch = hSwitch;
|
|
|
+ }
|
|
|
+ public AccessWrapper(HolonElement hElement){
|
|
|
+ type = HOLONELEMENT;
|
|
|
+ this.hElement = hElement;
|
|
|
+ }
|
|
|
+ public void setState(boolean state) {
|
|
|
+ if(type == HOLONELEMENT) {
|
|
|
+ hElement.setActive(state);
|
|
|
+ }else{//is switch
|
|
|
+ hSwitch.setManualMode(true);
|
|
|
+ hSwitch.setManualState(state);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ public boolean getState(int timeStep) {
|
|
|
+ return (type == HOLONELEMENT)?hElement.isActive():hSwitch.getState(timeStep);
|
|
|
+ }
|
|
|
+ public int getType() {
|
|
|
+ return type;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private class RunResult {
|
|
|
+ public int activatedFlex = 0;
|
|
|
+ public int deactivatedElements = 0;
|
|
|
+ public float totalCost = 0;
|
|
|
+ public LinkedList<TimeStepStateResult> timeStepList = new LinkedList<TimeStepStateResult>();
|
|
|
+
|
|
|
+
|
|
|
+ public TimeStepStateResult addTimeStepStateResult(){
|
|
|
+ TimeStepStateResult aResult = new TimeStepStateResult();
|
|
|
+ timeStepList.add(aResult);
|
|
|
+ return aResult;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public class TimeStepStateResult{
|
|
|
+ public int amountOfProducer = 0;
|
|
|
+ public int amountOfConsumer = 0;
|
|
|
+ public int amountOfPassiv = 0;
|
|
|
+ public int amountOfConsumerOverSupplied = 0;
|
|
|
+ public int amountOfConsumerSupplied = 0;
|
|
|
+ public int amountOfConsumerPartiallySupplied = 0;
|
|
|
+ public int amountOfConsumerUnSupplied= 0;
|
|
|
+
|
|
|
+ public float getProportionWithState(HolonObjectState state) {
|
|
|
+ float amountOfObjects = amountOfProducer + amountOfConsumer + amountOfPassiv;
|
|
|
+ switch(state) {
|
|
|
+ case NOT_SUPPLIED:
|
|
|
+ return (float) amountOfConsumerUnSupplied / amountOfObjects;
|
|
|
+ case NO_ENERGY:
|
|
|
+ return (float) amountOfPassiv / amountOfObjects;
|
|
|
+ case OVER_SUPPLIED:
|
|
|
+ return (float) amountOfConsumerOverSupplied / amountOfObjects;
|
|
|
+ case PARTIALLY_SUPPLIED:
|
|
|
+ return (float) amountOfConsumerPartiallySupplied / amountOfObjects;
|
|
|
+ case PRODUCER:
|
|
|
+ return (float) amountOfProducer / amountOfObjects;
|
|
|
+ case SUPPLIED:
|
|
|
+ return (float) amountOfConsumerSupplied / amountOfObjects;
|
|
|
+ default:
|
|
|
+ return 0.f;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ public float getAvergaeProportionWithState(HolonObjectState state) {
|
|
|
+ return timeStepList.stream().map(step -> step.getProportionWithState(state)).reduce((a,b) -> (a + b)).orElse(0.f) / (float) 100;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * To create Random and maybe switch the random generation in the future.
|
|
|
+ */
|
|
|
+ private static class Random{
|
|
|
+
|
|
|
+
|
|
|
+ private static java.util.Random random = new java.util.Random();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * True or false
|
|
|
+ * @return the random boolean.
|
|
|
+ */
|
|
|
+ public static boolean nextBoolean(){
|
|
|
+ return random.nextBoolean();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * Between 0.0(inclusive) and 1.0 (exclusive)
|
|
|
+ * @return the random double.
|
|
|
+ */
|
|
|
+ public static double nextDouble() {
|
|
|
+ return random.nextDouble();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Random Int in Range [min;max[ with UniformDistirbution
|
|
|
+ * @param min
|
|
|
+ * @param max
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static int nextIntegerInRange(int min, int max) {
|
|
|
+ return min + random.nextInt(max - min);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ private class Handle<T>{
|
|
|
+ public T object;
|
|
|
+ Handle(T object){
|
|
|
+ this.object = object;
|
|
|
+ }
|
|
|
+ public String toString() {
|
|
|
+ return object.toString();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|