package holeg.api; import holeg.addon.helper.EmailNotification; import holeg.algorithm.objective_function.ObjectiveFunctionByCarlos; import holeg.algorithm.objective_function.SwitchObjectiveFunction; import holeg.model.Flexibility; import holeg.model.Flexibility.FlexState; import holeg.model.GroupNode; import holeg.model.HolonElement; import holeg.model.HolonObject; import holeg.model.HolonSwitch; import holeg.model.HolonSwitch.SwitchMode; import holeg.model.HolonSwitch.SwitchState; import holeg.model.Model; import holeg.preferences.ImagePreference; import holeg.ui.controller.Control; import holeg.ui.view.component.Console; import holeg.ui.view.image.Import; import holeg.utility.math.decimal.Format; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.image.BufferedImage; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.math.RoundingMode; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collections; import java.util.DoubleSummaryStatistics; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JFormattedTextField; 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.text.NumberFormatter; public abstract class AlgorithmFrameworkFlex implements AddOn { //Algo protected int rounds = 1; protected Console console = new Console(); protected boolean cancel = false; //holeg interaction protected Control control; protected List runList = new LinkedList(); protected boolean useStepping = false; LinkedList> resetChain = new LinkedList>(); boolean algoUseElements = false, algoUseSwitches = true, algoUseFlexes = true, algoUseKillSwitch = true; //Parameter @SuppressWarnings("rawtypes") LinkedList parameterSteppingList = new LinkedList(); ObjectiveFunction evaluationFunction = ObjectiveFunction.Normal; //Panel private JPanel content = new JPanel(); private JPanel borderPanel = new JPanel(); //Settings groupNode private Optional groupNode = Optional.empty(); //access private ArrayList access; private HashMap accessKillSwitch = new HashMap(); //time private long startTime; private RunProgressBar runProgressbar = new RunProgressBar(); //concurrency private Thread runThread = new Thread(); //printing private Printer runPrinter = new Printer(plottFileName()); private RunAverage avg = new RunAverage(); //Email private boolean useEmailNotification = false; ; public AlgorithmFrameworkFlex() { 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(1200, 800)); } private 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)); borderPanel.setLayout(new BoxLayout(borderPanel, BoxLayout.PAGE_AXIS)); addIntParameter("Rounds", rounds, intInput -> rounds = intInput, () -> rounds, 1); JScrollPane scrollPane = new JScrollPane(borderPanel); scrollPane.setBounds(10, 0, 850, 292); scrollPane.setBorder(BorderFactory.createEmptyBorder()); parameterPanel.add(scrollPane); JButton selectGroupNodeButton = new JButton("Select GroupNode"); selectGroupNodeButton.setBounds(900, 0, 185, 30); selectGroupNodeButton.addActionListener(actionEvent -> selectGroupNode()); parameterPanel.add(selectGroupNodeButton); JProgressBar progressBar = runProgressbar.getJProgressBar(); progressBar.setBounds(900, 35, 185, 20); progressBar.setStringPainted(true); parameterPanel.add(progressBar); JCheckBox useElements = new JCheckBox("Elements"); useElements.setSelected(algoUseElements); useElements.setBounds(900, 70, 185, 20); useElements.addActionListener(actionEvent -> algoUseElements = useElements.isSelected()); parameterPanel.add(useElements); JCheckBox useSwitches = new JCheckBox("Switches"); useSwitches.setSelected(algoUseSwitches); useSwitches.setBounds(900, 90, 185, 20); useSwitches.addActionListener(actionEvent -> algoUseSwitches = useSwitches.isSelected()); parameterPanel.add(useSwitches); JCheckBox useFlexes = new JCheckBox("Flexibilities"); useFlexes.setSelected(algoUseFlexes); useFlexes.setBounds(900, 110, 185, 20); useFlexes.addActionListener(actionEvent -> algoUseFlexes = useFlexes.isSelected()); parameterPanel.add(useFlexes); JCheckBox useSmartMeter = new JCheckBox("SmartMeter"); useSmartMeter.setSelected(algoUseFlexes); useSmartMeter.setBounds(900, 130, 185, 20); useSmartMeter.addActionListener(actionEvent -> { cancel(); reset(); algoUseKillSwitch = useSmartMeter.isSelected(); }); parameterPanel.add(useSmartMeter); String[] objectiveFunctionStrings = {"Normal", "Switch"}; JLabel fitnessLabel = new JLabel("FitnessFunction:"); fitnessLabel.setBounds(910, 160, 90, 20); parameterPanel.add(fitnessLabel); JComboBox ofBox = new JComboBox(objectiveFunctionStrings); ofBox.addActionListener(actionEvent -> { boolean pickNormal = ((String) ofBox.getSelectedItem()).equals("Normal"); evaluationFunction = pickNormal ? ObjectiveFunction.Normal : ObjectiveFunction.Switch; }); ofBox.setBounds(1000, 160, 70, 20); parameterPanel.add(ofBox); JCheckBox emailNotificationCheckbox = new JCheckBox("EmailNotification"); emailNotificationCheckbox.setSelected(this.useEmailNotification); emailNotificationCheckbox.setBounds(900, 200, 130, 20); emailNotificationCheckbox.addActionListener( actionEvent -> useEmailNotification = emailNotificationCheckbox.isSelected()); parameterPanel.add(emailNotificationCheckbox); JButton emailSettingsButton = new JButton("", new ImageIcon(Import.loadImage(ImagePreference.Button.Settings, 16, 16))); emailSettingsButton.setBounds(1030, 200, 20, 20); emailSettingsButton.addActionListener(event -> { EmailNotification.OpenEmailSettings(content); }); parameterPanel.add(emailSettingsButton); return parameterPanel; } private JPanel createButtonPanel() { JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); JButton resetButton = new JButton("Reset"); resetButton.setToolTipText("Resets the state to the initial grid configuration."); resetButton.addActionListener(actionEvent -> reset()); buttonPanel.add(resetButton); JButton cancelButton = new JButton("Cancel Run"); cancelButton.addActionListener(actionEvent -> cancel()); buttonPanel.add(cancelButton); JButton fitnessButton = new JButton("Evaluate"); fitnessButton.setToolTipText("Evaluate the current grid configuration."); fitnessButton.addActionListener(actionEvent -> fitness()); buttonPanel.add(fitnessButton); JButton runButton = new JButton("Run"); runButton.addActionListener(actionEvent -> { Runnable task = () -> run(); runThread = new Thread(task); runThread.start(); }); buttonPanel.add(runButton); return buttonPanel; } //int protected void addIntParameter(String parameterName, int parameterValue, Consumer setter, Supplier getter) { this.addIntParameter(parameterName, parameterValue, setter, getter, Integer.MIN_VALUE, Integer.MAX_VALUE); } //ParameterImports protected void addIntParameter(String parameterName, int parameterValue, Consumer setter, Supplier getter, int parameterMinValue) { this.addIntParameter(parameterName, parameterValue, setter, getter, parameterMinValue, Integer.MAX_VALUE); } protected void addIntParameter(String parameterName, int parameterValue, Consumer setter, Supplier getter, int parameterMinValue, int parameterMaxValue) { JPanel singleParameterPanel = new JPanel(); singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS)); singleParameterPanel.setAlignmentX(0.0f); singleParameterPanel.add(new JLabel(parameterName + ": ")); singleParameterPanel.add(Box.createHorizontalGlue()); NumberFormat format = NumberFormat.getIntegerInstance(); format.setGroupingUsed(false); format.setParseIntegerOnly(true); NumberFormatter integerFormatter = new NumberFormatter(format); integerFormatter.setMinimum(parameterMinValue); integerFormatter.setMaximum(parameterMaxValue); integerFormatter.setCommitsOnValidEdit(true); JFormattedTextField singleParameterTextField = new JFormattedTextField(integerFormatter); singleParameterTextField.setValue(parameterValue); String minValue = (parameterMinValue == Integer.MIN_VALUE) ? "Integer.MIN_VALUE" : String.valueOf(parameterMinValue); String maxValue = (parameterMaxValue == Integer.MAX_VALUE) ? "Integer.MAX_VALUE" : String.valueOf(parameterMaxValue); singleParameterTextField.setToolTipText( "Only integer \u2208 [" + minValue + "," + maxValue + "]"); singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept( Integer.parseInt(singleParameterTextField.getValue().toString()))); singleParameterTextField.setMaximumSize(new Dimension(200, 30)); singleParameterTextField.setPreferredSize(new Dimension(200, 30)); singleParameterPanel.add(singleParameterTextField); ParameterStepping intParameterStepping = new ParameterStepping(setter, getter, Integer::sum, (a, b) -> a * b, 1, 1); intParameterStepping.useThisParameter = false; parameterSteppingList.add(intParameterStepping); JCheckBox useSteppingCheckBox = new JCheckBox(); useSteppingCheckBox.setSelected(false); singleParameterPanel.add(useSteppingCheckBox); JLabel stepsLabel = new JLabel("Steps: "); stepsLabel.setEnabled(false); singleParameterPanel.add(stepsLabel); NumberFormatter stepFormatter = new NumberFormatter(format); stepFormatter.setMinimum(1); stepFormatter.setMaximum(Integer.MAX_VALUE); stepFormatter.setCommitsOnValidEdit(true); JFormattedTextField stepsTextField = new JFormattedTextField(stepFormatter); stepsTextField.setEnabled(false); stepsTextField.setValue(1); stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]"); stepsTextField.addPropertyChangeListener( actionEvent -> intParameterStepping.stepps = Integer.parseInt( stepsTextField.getValue().toString())); stepsTextField.setMaximumSize(new Dimension(40, 30)); stepsTextField.setPreferredSize(new Dimension(40, 30)); singleParameterPanel.add(stepsTextField); JLabel stepsSizeLabel = new JLabel("Step size: "); stepsSizeLabel.setEnabled(false); singleParameterPanel.add(stepsSizeLabel); JFormattedTextField stepsSizeTextField = new JFormattedTextField(stepFormatter); stepsSizeTextField.setEnabled(false); stepsSizeTextField.setValue(1); stepsSizeTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]"); stepsSizeTextField.addPropertyChangeListener( actionEvent -> intParameterStepping.stepSize = Integer.parseInt( stepsSizeTextField.getValue().toString())); stepsSizeTextField.setMaximumSize(new Dimension(40, 30)); stepsSizeTextField.setPreferredSize(new Dimension(40, 30)); singleParameterPanel.add(stepsSizeTextField); useSteppingCheckBox.addActionListener(actionEvent -> { boolean enabled = useSteppingCheckBox.isSelected(); intParameterStepping.useThisParameter = enabled; this.useStepping = this.parameterSteppingList.stream() .anyMatch(parameter -> parameter.useThisParameter); stepsLabel.setEnabled(enabled); stepsTextField.setEnabled(enabled); stepsSizeLabel.setEnabled(enabled); stepsSizeTextField.setEnabled(enabled); }); borderPanel.add(singleParameterPanel); } //double protected void addDoubleParameter(String parameterName, double parameterValue, Consumer setter, Supplier getter) { this.addDoubleParameter(parameterName, parameterValue, setter, getter, Double.MIN_VALUE, Double.MAX_VALUE); } protected void addDoubleParameter(String parameterName, double parameterValue, Consumer setter, Supplier getter, double parameterMinValue) { this.addDoubleParameter(parameterName, parameterValue, setter, getter, parameterMinValue, Double.MAX_VALUE); } protected void addDoubleParameter(String parameterName, double parameterValue, Consumer setter, Supplier getter, double parameterMinValue, double parameterMaxValue) { JPanel singleParameterPanel = new JPanel(); singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS)); singleParameterPanel.setAlignmentX(0.0f); singleParameterPanel.add(new JLabel(parameterName + ": ")); singleParameterPanel.add(Box.createHorizontalGlue()); NumberFormat doubleFormat = NumberFormat.getNumberInstance(Locale.US); doubleFormat.setMinimumFractionDigits(1); doubleFormat.setMaximumFractionDigits(10); doubleFormat.setRoundingMode(RoundingMode.HALF_UP); NumberFormatter doubleFormatter = new NumberFormatter(doubleFormat); doubleFormatter.setMinimum(parameterMinValue); doubleFormatter.setMaximum(parameterMaxValue); doubleFormatter.setCommitsOnValidEdit(true); JFormattedTextField singleParameterTextField = new JFormattedTextField(doubleFormatter); singleParameterTextField.setValue(parameterValue); String minValue = (parameterMinValue == Double.MIN_VALUE) ? "Double.MIN_VALUE" : String.valueOf(parameterMinValue); String maxValue = (parameterMaxValue == Double.MAX_VALUE) ? "Double.MAX_VALUE" : String.valueOf(parameterMaxValue); singleParameterTextField.setToolTipText( "Only double \u2208 [" + minValue + "," + maxValue + "]"); singleParameterTextField.addPropertyChangeListener(actionEvent -> setter.accept( Double.parseDouble(singleParameterTextField.getValue().toString()))); singleParameterTextField.setMaximumSize(new Dimension(200, 30)); singleParameterTextField.setPreferredSize(new Dimension(200, 30)); singleParameterPanel.add(singleParameterTextField); ParameterStepping doubleParameterStepping = new ParameterStepping(setter, getter, (a, b) -> a + b, (a, b) -> a * b, 1.0, 1); doubleParameterStepping.useThisParameter = false; parameterSteppingList.add(doubleParameterStepping); JCheckBox useSteppingCheckBox = new JCheckBox(); useSteppingCheckBox.setSelected(false); singleParameterPanel.add(useSteppingCheckBox); JLabel stepsLabel = new JLabel("Steps: "); stepsLabel.setEnabled(false); singleParameterPanel.add(stepsLabel); NumberFormat format = NumberFormat.getIntegerInstance(); format.setGroupingUsed(false); format.setParseIntegerOnly(true); NumberFormatter integerFormatter = new NumberFormatter(format); integerFormatter.setMinimum(1); integerFormatter.setMaximum(Integer.MAX_VALUE); integerFormatter.setCommitsOnValidEdit(true); JFormattedTextField stepsTextField = new JFormattedTextField(integerFormatter); stepsTextField.setEnabled(false); stepsTextField.setValue(1); stepsTextField.setToolTipText("Only integer \u2208 [" + 1 + "," + Integer.MAX_VALUE + "]"); stepsTextField.addPropertyChangeListener( actionEvent -> doubleParameterStepping.stepps = Integer.parseInt( stepsTextField.getValue().toString())); stepsTextField.setMaximumSize(new Dimension(40, 30)); stepsTextField.setPreferredSize(new Dimension(40, 30)); singleParameterPanel.add(stepsTextField); JLabel stepsSizeLabel = new JLabel("Step size: "); stepsSizeLabel.setEnabled(false); singleParameterPanel.add(stepsSizeLabel); NumberFormatter doubleFormatterForStepping = new NumberFormatter(doubleFormat); doubleFormatterForStepping.setCommitsOnValidEdit(true); JFormattedTextField stepsSizeTextField = new JFormattedTextField(doubleFormatterForStepping); stepsSizeTextField.setEnabled(false); stepsSizeTextField.setValue(1.0); stepsSizeTextField.setToolTipText("Only double"); stepsSizeTextField.addPropertyChangeListener( actionEvent -> doubleParameterStepping.stepSize = Double.parseDouble( stepsSizeTextField.getValue().toString())); stepsSizeTextField.setMaximumSize(new Dimension(40, 30)); stepsSizeTextField.setPreferredSize(new Dimension(40, 30)); singleParameterPanel.add(stepsSizeTextField); useSteppingCheckBox.addActionListener(actionEvent -> { boolean enabled = useSteppingCheckBox.isSelected(); doubleParameterStepping.useThisParameter = enabled; this.useStepping = this.parameterSteppingList.stream() .anyMatch(parameter -> parameter.useThisParameter); stepsLabel.setEnabled(enabled); stepsTextField.setEnabled(enabled); stepsSizeLabel.setEnabled(enabled); stepsSizeTextField.setEnabled(enabled); }); borderPanel.add(singleParameterPanel); } //boolean protected void addBooleanParameter(String parameterName, boolean parameterValue, Consumer setter) { JPanel singleParameterPanel = new JPanel(); singleParameterPanel.setLayout(new BoxLayout(singleParameterPanel, BoxLayout.LINE_AXIS)); singleParameterPanel.setAlignmentX(0.0f); singleParameterPanel.add(new JLabel(parameterName + ": ")); singleParameterPanel.add(Box.createHorizontalGlue()); JCheckBox useGroupNodeCheckBox = new JCheckBox(); useGroupNodeCheckBox.setSelected(parameterValue); useGroupNodeCheckBox.addActionListener( actionEvent -> setter.accept(useGroupNodeCheckBox.isSelected())); singleParameterPanel.add(useGroupNodeCheckBox); borderPanel.add(singleParameterPanel); } private void startTimer() { startTime = System.currentTimeMillis(); } private long printElapsedTime() { long elapsedMilliSeconds = System.currentTimeMillis() - startTime; console.println("Execution Time in Milliseconds:" + elapsedMilliSeconds); return elapsedMilliSeconds; } private void cancel() { if (runThread.isAlive()) { console.println("Cancel run."); cancel = true; runProgressbar.cancel(); } else { console.println("Nothing to cancel."); } } private void fitness() { if (runThread.isAlive()) { console.println("Run have to be cancelled first."); return; } double currentFitness = evaluatePosition(extractPositionAndAccess()); resetChain.removeLast(); console.println("Actual Fitnessvalue: " + currentFitness); } private void selectGroupNode() { Object[] possibilities = control.getModel().getCanvas().getAllGroupNodeObjectsRecursive() .toArray(); @SuppressWarnings("unchecked") GroupNode selected = (GroupNode) JOptionPane.showInputDialog(content, "Select GroupNode:", "GroupNode?", JOptionPane.OK_OPTION, new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)), possibilities, ""); if (selected != null) { console.println("Selected: " + selected); groupNode = Optional.of(selected); } } protected double evaluatePosition(List positionToEvaluate) { runProgressbar.step(); setState(positionToEvaluate); // execution time critical double result = evaluateState(); return result; } private double evaluateState() { switch (this.evaluationFunction) { case Switch: return SwitchObjectiveFunction.getFitnessValueForState(control.getModel()); case Normal: default: return ObjectiveFunctionByCarlos.getFitnessValueForState(control.getModel()); } } private void run() { cancel = false; control.guiSetEnabled(false); runPrinter.openStream(); runPrinter.println(""); runPrinter.println("Start:" + stringStatFromRunValues(getRunValuesFromActualState())); runPrinter.closeStream(); if (this.useStepping) { initParameterStepping(); do { executeAlgoWithParameter(); if (cancel) { break; } resetState(); } while (updateOneParameter()); resetParameterStepping(); } else { executeAlgoWithParameter(); } updateVisual(); runProgressbar.finishedCancel(); control.guiSetEnabled(true); if (this.useEmailNotification && !cancel) { EmailNotification.sendEmail(this.getClass().getName() + " finished", "Execution done."); } } @SuppressWarnings("rawtypes") private void initParameterStepping() { for (ParameterStepping param : this.parameterSteppingList) { param.init(); } } @SuppressWarnings("rawtypes") private void resetParameterStepping() { for (ParameterStepping param : this.parameterSteppingList) { param.reset(); } } @SuppressWarnings("rawtypes") private boolean updateOneParameter() { List parameterInUseList = this.parameterSteppingList.stream() .filter(param -> param.useThisParameter).collect(Collectors.toList()); Collections.reverse(parameterInUseList); int lastParameter = parameterInUseList.size() - 1; int actualParameter = 0; for (ParameterStepping param : parameterInUseList) { if (param.canUpdate()) { param.update(); return true; } else { if (actualParameter == lastParameter) { break; } param.reset(); } actualParameter++; } //No Param can be updated return false; } private void executeAlgoWithParameter() { double startFitness = evaluatePosition(extractPositionAndAccess()); console.println("BitLength: " + access.size()); resetChain.removeLast(); runPrinter.openStream(); runPrinter.println(algoInformationToPrint()); console.println(algoInformationToPrint()); runPrinter.closeStream(); runProgressbar.start(); Individual runBest = new Individual(); runBest.fitness = Double.MAX_VALUE; this.avg = new RunAverage(); for (int r = 0; r < rounds; r++) { startTimer(); Individual roundBest = executeAlgo(); if (cancel) { return; } long executionTime = printElapsedTime(); setState(roundBest.position); runPrinter.openStream(); runPrinter.println(runList.stream().map(value -> Format.doubleFixedPlaces(2, value)) .collect(Collectors.joining(", "))); RunValues val = getRunValuesFromActualState(); val.result = roundBest.fitness; val.executionTime = executionTime; avg.addRun(val); runPrinter.println( "Result: " + Format.doubleFixedPlaces(2, roundBest.fitness) + " ExecutionTime:" + executionTime + " " + stringStatFromRunValues(val)); runPrinter.closeStream(); resetState(); if (roundBest.fitness < runBest.fitness) { runBest = roundBest; } } this.extractPositionAndAccess(); setState(runBest.position); updateVisual(); console.println("Start: " + Format.doubleFixedPlaces(2, startFitness)); console.println("AlgoResult: " + Format.doubleFixedPlaces(2, runBest.fitness)); if (this.algoUseFlexes) { calculateAndPrintFlexInfos(); } runPrinter.openStream(); if (rounds > 1) { RunValues avgRun = avg.getAverage(); runPrinter.println("Average.Result: " + Format.doubleFixedPlaces(2, avgRun.result) + " Average.ExecutionTime:" + avgRun.executionTime + " " + avg.getAverage() .stringStatFromRunValues("Average.")); } runPrinter.println(""); runPrinter.closeStream(); } private void calculateAndPrintFlexInfos() { int amountOfUsedFlex = 0; List allFlex = control.getModel().getAllFlexibilities(); int amountOfFlex = allFlex.size(); float cost = 0; int consumingFlex = 0; float consumingFlexEnergy = 0.0f; int producingFlex = 0; float producingFlexEnergy = 0.0f; int maxCooldown = 0; int amountEssential = 0; int amountHigh = 0; int amountMedium = 0; int amountLow = 0; Stream allFlexInUse = allFlex.stream() .filter(flex -> flex.getState().equals(FlexState.IN_USE)); Iterator iterInUseFlex = allFlexInUse.iterator(); while (iterInUseFlex.hasNext()) { Flexibility flex = iterInUseFlex.next(); amountOfUsedFlex++; cost += flex.cost; float energy = flex.energyReleased(); if (energy < 0) { consumingFlex++; consumingFlexEnergy += -energy; } else { producingFlex++; producingFlexEnergy += energy; } if (flex.getCooldown() > maxCooldown) { maxCooldown = flex.getCooldown(); } switch (flex.getElement().getPriority()) { case Essential: amountEssential++; break; case High: amountHigh++; break; case Low: amountLow++; break; case Medium: amountMedium++; break; default: break; } } //Total Flexibilities: //Used Flexibilities: console.println("Used Flex [" + amountOfUsedFlex + "/" + amountOfFlex + "]"); //Consuming Flexibilities: console.println( consumingFlex + " consuimg flexibilities that consumed " + consumingFlexEnergy + "Energy."); //Producing Flexibilities console.println( producingFlex + " producing flexibilities that produce " + producingFlexEnergy + "Energy."); console.println( "Flex in use:\t" + "Low= " + amountLow + "\tMedium= " + amountMedium + "\tHigh= " + amountHigh + "\tEssential= " + amountEssential); //Total cost: console.println("Total Cost: " + cost); //Longest Cooldown console.println("Max Cooldown: " + maxCooldown); // } protected abstract Individual executeAlgo(); private void reset() { if (runThread.isAlive()) { console.println("Run have to be cancelled First."); return; } if (!resetChain.isEmpty()) { console.println("Resetting.."); setState(resetChain.getFirst()); resetChain.clear(); control.resetSimulation(); control.getModel().setCurrentIteration(0); updateVisual(); } else { console.println("No run inistialized."); } } /** * To let the User See the current state without touching the Canvas. */ private void updateVisual() { control.updateStateForCurrentIteration(); } /** * 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 position) { control.resetSimulation(); int i = 0; for (Boolean bool : position) { access.get(i++).setState(bool); } control.calculateStateForCurrentIteration(); } /** * 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. * * @return */ protected List extractPositionAndAccess() { Model model = control.getModel(); this.accessKillSwitch = new HashMap(); access = new ArrayList(); List initialState = new ArrayList(); rollOutNodes(initialState); resetChain.add(initialState); if (algoUseFlexes) { List flexList = model.getAllFlexibilities(); List allOfferedFLex = flexList.stream() .filter(flex -> flex.getState() == FlexState.OFFERED).toList(); for (Flexibility flex : allOfferedFLex) { //flex.getFlex().getElement().parentObject; AccessWrapper killSwitchAccess = this.algoUseKillSwitch ? this.accessKillSwitch.get(flex.getElement().parentObject) : null; ; access.add(new AccessWrapper(flex, killSwitchAccess)); initialState.add(false); } List allInUseFLex = flexList.stream() .filter(flex -> flex.getState() == FlexState.IN_USE).toList(); for (Flexibility flex : allInUseFLex) { AccessWrapper killSwitchAccess = this.algoUseKillSwitch ? this.accessKillSwitch.get(flex.getElement().parentObject) : null; access.add(new AccessWrapper(flex, killSwitchAccess)); initialState.add(true); } } //console.println(access.stream().map(Object::toString).collect(Collectors.joining(", "))); return initialState; } private void rollOutNodes(List positionToInit) { boolean groupNodeSelected = groupNode.isPresent(); int timeStep = control.getModel().getCurrentIteration(); Stream holonObjects = groupNodeSelected ? groupNode.get().getAllHolonObjectsRecursive() : control.getModel().getCanvas().getAllHolonObjectsRecursive(); Stream holonSwitches = groupNodeSelected ? groupNode.get().getAllSwitchObjectsRecursive() : control.getModel().getCanvas().getAllSwitchObjectsRecursive(); holonObjects.forEach(hObject -> { AccessWrapper killSwitchAccess = new AccessWrapper(hObject); if (this.algoUseKillSwitch) { positionToInit.add(false); access.add(killSwitchAccess); accessKillSwitch.put(hObject, killSwitchAccess); } if (this.algoUseElements) { hObject.elementsStream().forEach(hE -> { positionToInit.add(hE.active); access.add(new AccessWrapper(hE, killSwitchAccess)); }); } }); holonSwitches.forEach(sw -> { positionToInit.add(sw.getState().isClosed()); access.add(new AccessWrapper(sw)); }); } private RunValues getRunValuesFromActualState() { RunValues val = new RunValues(); GroupNode canvas = control.getModel().getCanvas(); List holonObjectList = canvas.getAllHolonObjectsRecursive().toList(); Map stateMap = holonObjectList.stream() .collect(Collectors.groupingBy(HolonObject::getState, Collectors.counting())); // UPDATE SUPPLY STATE val.producer = Math.toIntExact( stateMap.getOrDefault(HolonObject.HolonObjectState.PRODUCER, 0L)); val.overSupplied = Math.toIntExact( stateMap.getOrDefault(HolonObject.HolonObjectState.OVER_SUPPLIED, 0L)); val.supplied = Math.toIntExact( stateMap.getOrDefault(HolonObject.HolonObjectState.SUPPLIED, 0L)); val.partiallySupplied = Math.toIntExact( stateMap.getOrDefault(HolonObject.HolonObjectState.PARTIALLY_SUPPLIED, 0L)); val.unsupplied = Math.toIntExact( stateMap.getOrDefault(HolonObject.HolonObjectState.NOT_SUPPLIED, 0L)); val.passiv = Math.toIntExact(stateMap.getOrDefault(HolonObject.HolonObjectState.NO_ENERGY, 0L)); val.consumer = val.overSupplied + val.supplied + val.partiallySupplied + val.unsupplied; val.objects = val.consumer + val.producer + val.passiv; List holonElementList = canvas.getAllHolonElements().toList(); val.elements = holonElementList.size(); // UPDATE ActiveInActive val.activeElements = holonElementList.stream().filter(HolonElement::isOn).count(); val.consumption = canvas.getTotalConsumption(); val.production = canvas.getTotalProduction(); val.difference = Math.abs(val.production - val.consumption); List activeFlex = holonElementList.stream().flatMap(ele -> ele.flexList.stream()) .filter(flex -> flex.getState().equals(FlexState.IN_USE)).toList(); Map priorityCounts = activeFlex.stream() .collect(Collectors.groupingBy(flex -> flex.getElement().priority, Collectors.counting())); val.essentialFlex = priorityCounts.getOrDefault(HolonElement.Priority.Essential, 0L); val.highFlex = priorityCounts.getOrDefault(HolonElement.Priority.High, 0L); val.mediumFlex = priorityCounts.getOrDefault(HolonElement.Priority.Medium, 0L); val.lowFlex = priorityCounts.getOrDefault(HolonElement.Priority.Low, 0L); val.flexebilities = activeFlex.size(); val.holon = control.getModel().holons.size(); List switchList = canvas.getAllSwitchObjectsRecursive().toList(); val.switches = switchList.size(); val.activeSwitches = (int) switchList.stream().filter(HolonSwitch::isClosed).count(); DoubleSummaryStatistics overStat = holonObjectList.stream() .filter(con -> con.getState().equals(HolonObject.HolonObjectState.OVER_SUPPLIED)) .mapToDouble(HolonObject::getSupplyBarPercentage).summaryStatistics(); DoubleSummaryStatistics partiallyStat = holonObjectList.stream() .filter(con -> con.getState().equals(HolonObject.HolonObjectState.PARTIALLY_SUPPLIED)) .mapToDouble(HolonObject::getSupplyBarPercentage).summaryStatistics(); val.partiallyMin = RunValues.filterInf(partiallyStat.getMin()); val.partiallyMax = RunValues.filterInf(partiallyStat.getMax()); val.partiallyAverage = RunValues.filterInf(partiallyStat.getAverage()); val.overMin = RunValues.filterInf(overStat.getMin()); val.overMax = RunValues.filterInf(overStat.getMax()); val.overAverage = RunValues.filterInf(overStat.getAverage()); return val; } private String stringStatFromRunValues(RunValues val) { return val.stringStatFromRunValues(""); } @Override public JPanel getPanel() { return content; } @Override public void setController(Control control) { this.control = control; } protected abstract int getProgressBarMaxCount(); protected abstract String algoInformationToPrint(); protected abstract String plottFileName(); //ObjectiveFunction enum ObjectiveFunction {Normal, Switch} private enum AccessType {None, HolonElement, Switch, Flexibility, KillSwitch} static class RunValues { public double result; public double executionTime; public double objects; public double passiv; public double consumer; public double supplied; public double producer; public double unsupplied; public double partiallySupplied; public double overSupplied; public double partiallyMin; public double partiallyMax; public double partiallyAverage; public double overMin; public double overMax; public double overAverage; public double activeElements; public double elements; public double essentialFlex; public double highFlex; public double mediumFlex; public double lowFlex; public double flexebilities; public double switches; public double activeSwitches; public double holon; public double consumption; public double production; public double difference; public static double filterInf(double value) { if (value == Double.NEGATIVE_INFINITY || value == Double.POSITIVE_INFINITY || Double.isNaN( value)) { return 0; } else { return value; } } public static String percentage(double numerator, double denominator) { if ((int) denominator == 0) { return "-%"; } return Format.doubleTwoPlaces(numerator) + "/" + Format.doubleTwoPlaces(denominator) + " " + Format.doubleFixedPlaces(2, (float) numerator / (float) denominator * 100) + "%"; } public String stringStatFromRunValues(String prefix) { return prefix + "Passiv: " + percentage(passiv, objects) + " " + prefix + "Producer: " + percentage(producer, objects) + " " + prefix + "Consumer: " + percentage(consumer, objects) + " " + prefix + "Unsupplied: " + percentage(unsupplied, objects) + " " + prefix + "Partially: " + percentage(partiallySupplied, objects) + " " + prefix + "Over: " + percentage(overSupplied, objects) + " " + prefix + "Supplied: " + percentage(supplied, objects) + " " + prefix + "Partially.SupplyPercentage.Min: " + Format.doubleFixedPlaces(2, partiallyMin) + " " + prefix + "Partially.SupplyPercentage.Max: " + Format.doubleFixedPlaces(2, partiallyMax) + " " + prefix + "Partially.SupplyPercentage.Average: " + Format.doubleFixedPlaces(2, partiallyAverage) + " " + prefix + "Over.SupplyPercentage.Min: " + Format.doubleFixedPlaces(2, overMin) + " " + prefix + "Over.SupplyPercentage.Max: " + Format.doubleFixedPlaces(2, overMax) + " " + prefix + "Over.SupplyPercentage.Average: " + Format.doubleFixedPlaces(2, overAverage) + " " + prefix + "HolonElemnts.Active:" + percentage(activeElements, elements) + " " + prefix + "Flexibilities.Essential: " + percentage(essentialFlex, flexebilities) + " " + prefix + "Flexibilities.High: " + percentage(highFlex, flexebilities) + " " + prefix + "Flexibilities.Medium: " + percentage(mediumFlex, flexebilities) + " " + prefix + "Flexibilities.Low: " + percentage(lowFlex, flexebilities) + " " + prefix + "Switches.Active:" + percentage(activeSwitches, switches) + " " + prefix + "Holons: " + holon + " " + prefix + "TotalConsumption: " + consumption + " " + prefix + "TotalProduction: " + production + " " + prefix + "Difference: " + difference; } } /** * To create Random and maybe switch the random generation in the future. */ protected 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) { int result = min; try { result = min + random.nextInt(max - min); } catch (java.lang.IllegalArgumentException e) { System.err.println("min : " + min + " max : " + max); System.err.println("max should be more then min"); } return result; } } private class RunProgressBar { //progressbar private JProgressBar progressBar = new JProgressBar(); private int count = 0; private boolean isActive = false; public void step() { if (isActive) { progressBar.setValue(count++); } } public void start() { progressBar.setIndeterminate(false); count = 0; isActive = true; progressBar.setValue(0); progressBar.setMaximum(getProgressBarMaxCount()); } public void cancel() { isActive = false; progressBar.setIndeterminate(true); } public void finishedCancel() { progressBar.setIndeterminate(false); progressBar.setValue(0); } public JProgressBar getJProgressBar() { return progressBar; } } public class Printer { private JFileChooser fileChooser = new JFileChooser(); private BufferedWriter out; public Printer(String filename) { fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir"))); fileChooser.setSelectedFile(new File(filename)); } public void openStream() { File file = fileChooser.getSelectedFile(); try { file.createNewFile(); out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(file, true), "UTF-8")); } catch (IOException e) { System.out.println(e.getMessage()); } } public void println(String stringToPrint) { try { out.write(stringToPrint); out.newLine(); } catch (IOException e) { System.out.println(e.getMessage()); } } public void closeStream() { try { out.close(); } catch (IOException e) { System.out.println(e.getMessage()); } } } ; private class RunAverage { private int runCount = 0; //Values private RunValues sum = new RunValues(); public void addRun(RunValues val) { sum.result += val.result; sum.executionTime += val.executionTime; sum.passiv += val.passiv; sum.consumer += val.consumer; sum.producer += val.producer; sum.unsupplied += val.unsupplied; sum.partiallySupplied += val.partiallySupplied; sum.overSupplied += val.overSupplied; sum.activeElements += val.activeElements; sum.elements += val.elements; sum.essentialFlex += val.essentialFlex; sum.highFlex += val.highFlex; sum.mediumFlex += val.mediumFlex; sum.lowFlex += val.lowFlex; sum.flexebilities += val.flexebilities; sum.holon += val.holon; sum.switches += val.switches; sum.activeSwitches += val.activeSwitches; sum.consumption += val.consumption; sum.production += val.production; sum.difference += val.difference; sum.objects += val.objects; sum.supplied += val.supplied; sum.partiallyMin += val.partiallyMin; sum.partiallyMax += val.partiallyMax; sum.partiallyAverage += val.partiallyAverage; sum.overMin += val.overMin; sum.overMax += val.overMax; sum.overAverage += val.overAverage; runCount++; } public RunValues getAverage() { RunValues avg = new RunValues(); if (runCount == 0) { return avg; } avg.result = sum.result / runCount; avg.executionTime = sum.executionTime / runCount; avg.passiv = sum.passiv / runCount; avg.consumer = sum.consumer / runCount; avg.producer = sum.producer / runCount; avg.unsupplied = sum.unsupplied / runCount; avg.partiallySupplied = sum.partiallySupplied / runCount; avg.overSupplied = sum.overSupplied / runCount; avg.activeElements = sum.activeElements / runCount; avg.elements = sum.elements / runCount; avg.essentialFlex = sum.essentialFlex / runCount; avg.highFlex = sum.highFlex / runCount; avg.mediumFlex = sum.mediumFlex / runCount; avg.lowFlex = sum.lowFlex / runCount; avg.flexebilities = sum.flexebilities / runCount; avg.holon = sum.holon / runCount; avg.switches = sum.switches / runCount; avg.activeSwitches = sum.activeSwitches / runCount; avg.consumption = sum.consumption / runCount; avg.production = sum.production / runCount; avg.difference = sum.difference / runCount; avg.objects = sum.objects / runCount; avg.supplied = sum.supplied / runCount; avg.supplied = sum.supplied / runCount; avg.partiallyMin = sum.partiallyMin / runCount; avg.partiallyMax = sum.partiallyMax / runCount; avg.partiallyAverage = sum.partiallyAverage / runCount; avg.overMin = sum.overMin / runCount; avg.overMax = sum.overMax / runCount; avg.overAverage = sum.overAverage / runCount; return avg; } } /** * A Wrapper Class for Access HolonElement and HolonSwitch in one Element and not have to split * the List. */ private class AccessWrapper { private AccessType type; private List intialStatesOfElementForKilllSwitch; private HolonObject hObject; private HolonSwitch hSwitch; private HolonElement hElement; private Flexibility flex; private AccessWrapper correspondingKillSwitch; private boolean lastState; public AccessWrapper(HolonObject hObject) { type = AccessType.KillSwitch; this.hObject = hObject; intialStatesOfElementForKilllSwitch = new ArrayList(); hObject.elementsStream().forEach(hE -> { intialStatesOfElementForKilllSwitch.add(hE.active); }); } public AccessWrapper(HolonSwitch hSwitch) { type = AccessType.Switch; this.hSwitch = hSwitch; } public AccessWrapper(HolonElement hElement, AccessWrapper correspondingKillSwitch) { type = AccessType.HolonElement; this.hElement = hElement; this.correspondingKillSwitch = correspondingKillSwitch; } public AccessWrapper(Flexibility flex, AccessWrapper correspondingKillSwitch) { type = AccessType.Flexibility; this.flex = flex; this.correspondingKillSwitch = correspondingKillSwitch; } public void setState(boolean state) { lastState = state; switch (type) { case HolonElement: if (!algoUseKillSwitch || (algoUseKillSwitch && !correspondingKillSwitch.getLastState())) { hElement.active = state; } break; case Switch: hSwitch.setMode(SwitchMode.Manual); hSwitch.setManualState(state ? SwitchState.Closed : SwitchState.Open); break; case Flexibility: if (state && (!algoUseKillSwitch || (algoUseKillSwitch && !correspondingKillSwitch.getLastState()))) { flex.order(); } break; case KillSwitch: if (state) { hObject.elementsStream().forEach(hE -> { hE.active = false; }); } else { List eleList = hObject.elementsStream().toList(); for (int i = 0; i < eleList.size(); i++) { eleList.get(i).active = intialStatesOfElementForKilllSwitch.get(i); } } break; default: break; } } public boolean getLastState() { return lastState; } public String typeString() { switch (type) { case HolonElement: return "HolonElement"; case Switch: return "Switch"; case Flexibility: return "Flexibility"; case KillSwitch: return "KillSwitch"; default: return "unknown"; } } public String toString() { return "[" + typeString() + "]"; } } private class Handle { public T object; Handle(T object) { this.object = object; } public String toString() { return object.toString(); } } public class Individual { public double fitness; public List position; public Individual() { } ; /** * Copy Constructor */ public Individual(Individual c) { position = c.position.stream().collect(Collectors.toList()); fitness = c.fitness; } String positionToString() { return position.stream().map(bool -> (bool ? "1" : "0")).collect(Collectors.joining()); } } protected class ParameterStepping { boolean useThisParameter = false; String paramaterName; int stepps; T stepSize; T startValue; Consumer setter; Supplier getter; BiFunction multyply; BiFunction add; private int count = 0; ParameterStepping(Consumer setter, Supplier getter, BiFunction add, BiFunction multyply, T stepSize, int stepps) { this.setter = setter; this.getter = getter; this.multyply = multyply; this.add = add; this.stepSize = stepSize; this.stepps = stepps; } void init() { startValue = getter.get(); } boolean canUpdate() { return count < stepps; } void update() { if (canUpdate()) { setter.accept(add.apply(startValue, multyply.apply(count + 1, stepSize))); count++; } } void reset() { setter.accept(startValue); count = 0; } } }