From 44e11a1a3ead1153d0797744afdf95dba2a95563 Mon Sep 17 00:00:00 2001 From: Philipp Spohr <spohr.philipp@web.de> Date: Sat, 19 Aug 2017 17:42:04 +0200 Subject: [PATCH] Added a GUI component for choosing number of solutions smaller fixes --- .../ba/yoshikoWrapper/core/AlgorithmTask.java | 36 ++++++++++++++----- .../ba/yoshikoWrapper/core/NetworkParser.java | 2 -- .../ba/yoshikoWrapper/core/YoshikoLoader.java | 2 ++ .../ba/yoshikoWrapper/gui/ClusterView.java | 1 - .../ba/yoshikoWrapper/gui/ComfortPanel.java | 7 ++-- .../ba/yoshikoWrapper/gui/FormatHelper.java | 9 +++-- .../yoshikoWrapper/gui/IntegerInputField.java | 9 +++-- .../hhu/ba/yoshikoWrapper/gui/MainPanel.java | 31 ++++++++++++++-- .../gui/SolutionNumberChooser.java | 26 ++++++++++++++ .../ba/yoshikoWrapper/gui/SolutionsPanel.java | 9 ++++- .../yoshikoWrapper/gui/TimeLimitSetter.java | 18 ++++++++-- .../yoshikoWrapper/swig/LibraryInterface.java | 12 +++++-- .../swig/LibraryInterfaceJNI.java | 2 ++ src/main/resources/YoshikoStrings.properties | 7 +++- 14 files changed, 145 insertions(+), 26 deletions(-) create mode 100644 src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionNumberChooser.java diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/core/AlgorithmTask.java b/src/main/java/de/hhu/ba/yoshikoWrapper/core/AlgorithmTask.java index c0c423f..fd1bcbd 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/core/AlgorithmTask.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/core/AlgorithmTask.java @@ -1,5 +1,4 @@ package de.hhu.ba.yoshikoWrapper.core; -//TODO: ADD LOGGER SYSTEM import org.cytoscape.model.CyColumn; import org.cytoscape.model.CyNetwork; @@ -35,7 +34,11 @@ public class AlgorithmTask extends AbstractTask { private boolean separatePartitionCuts; private boolean separateTriangles; private boolean useHeuristic; + private int numberOfSolutions; private SolutionsPanel solutionsPanel; + + //temps + private SWIGTYPE_p_yskInput__LibraryInput input; public AlgorithmTask( CyNetwork net, @@ -50,6 +53,7 @@ public class AlgorithmTask extends AbstractTask { boolean separatePartitionCuts, boolean separateTriangles, boolean useHeuristic, + int numberOfSolutions, SolutionsPanel solutionsPanel ) { @@ -65,6 +69,7 @@ public class AlgorithmTask extends AbstractTask { this.separatePartitionCuts = separatePartitionCuts; this.separateTriangles = separateTriangles; this.useHeuristic = useHeuristic; + this.numberOfSolutions = numberOfSolutions; this.solutionsPanel = solutionsPanel; } @@ -86,7 +91,7 @@ public class AlgorithmTask extends AbstractTask { taskMonitor.setProgress(0.1); //Generate an input instance from the network - SWIGTYPE_p_yskInput__LibraryInput input = NetworkParser.parseNetwork( + input = NetworkParser.parseNetwork( net, nodeMap, weightColumn, @@ -102,24 +107,24 @@ public class AlgorithmTask extends AbstractTask { //Call Yoshiko <<< Algorithm is performed here CyCore.currentSolutions = LibraryInterface.processLibraryInput( input, - 1, + numberOfSolutions, bitMaskRules, multiplicativeFactor, separatePartitionCuts, separateTriangles, useHeuristic - ); + ); + taskMonitor.setProgress(0.9); this.solutionsPanel.reset(); - long numberOfSolutions = LibraryInterface.ClusterEditingSolutions_getNumberOfSolutions(CyCore.currentSolutions); taskMonitor.setStatusMessage("Found: "+numberOfSolutions+" solutions!"); double modificationCost = LibraryInterface.ClusterEditingSolutions_getTotalCost(CyCore.currentSolutions); taskMonitor.setStatusMessage(LocalizationManager.get("paidCost")+modificationCost); - + solutionsPanel.setCost(modificationCost); for (long i=0;i<numberOfSolutions;i++) { taskMonitor.setStatusMessage("Processing solution "+(i+1)+" of "+numberOfSolutions); @@ -154,7 +159,22 @@ public class AlgorithmTask extends AbstractTask { } } - LibraryInterface.delete_LibraryInput(input); - taskMonitor.setProgress(1.0); + LibraryInterface.delete_LibraryInput(input); + input = null; + + //Provide some useful info + if (LibraryInterface.ClusterEditingSolutions_isTimedOut(CyCore.currentSolutions)) { + throw new Exception(LocalizationManager.get("timedOutMessage")); + } + + + } + + @Override + public void cancel() { + if (input != null) { + LibraryInterface.delete_LibraryInput(input); + } + super.cancel(); } } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/core/NetworkParser.java b/src/main/java/de/hhu/ba/yoshikoWrapper/core/NetworkParser.java index 8c3fd59..62079e0 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/core/NetworkParser.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/core/NetworkParser.java @@ -75,8 +75,6 @@ public class NetworkParser { } } - System.out.println("Found Edge: "+edgeEntry.get("name", String.class)+ " with weight:"+weight); - logger.debug("Found Edge: "+edgeEntry.get("name", String.class)+ " with weight:"+weight); LibraryInterface.LibraryInput_addEdge( diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/core/YoshikoLoader.java b/src/main/java/de/hhu/ba/yoshikoWrapper/core/YoshikoLoader.java index fc42a4d..0934c7c 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/core/YoshikoLoader.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/core/YoshikoLoader.java @@ -5,6 +5,7 @@ import java.io.File; import org.slf4j.Logger; import de.hhu.ba.yoshikoWrapper.logging.YoshikoLogger; +import de.hhu.ba.yoshikoWrapper.swig.LibraryInterface; public class YoshikoLoader { @@ -32,6 +33,7 @@ public class YoshikoLoader { //e.printStackTrace(); return; } + LibraryInterface.setVerbosity(3); isLoaded = true; } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ClusterView.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ClusterView.java index fc3ffa0..5893ac4 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ClusterView.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ClusterView.java @@ -85,7 +85,6 @@ public class ClusterView extends ComfortPanel { for (CyRow r: allRows) { r.set("selected", false); } - //Select nodes corresponding to the cluster for (CyNode n : nodes) { CyCore.cy.getCurrentNetwork().getRow(n).set("selected", true); diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ComfortPanel.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ComfortPanel.java index e2e320d..dbe4b53 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ComfortPanel.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/ComfortPanel.java @@ -3,6 +3,10 @@ package de.hhu.ba.yoshikoWrapper.gui; import javax.swing.JComponent; import javax.swing.JPanel; +/** + * Custom extension of the standard JPanel that provides some comfort functions + * + */ @SuppressWarnings("serial") public class ComfortPanel extends JPanel { @@ -15,6 +19,5 @@ public class ComfortPanel extends JPanel { this.add(c); } - } - + } } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/FormatHelper.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/FormatHelper.java index 48aed6c..e85294a 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/FormatHelper.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/FormatHelper.java @@ -8,11 +8,15 @@ import javax.swing.text.NumberFormatter; public class FormatHelper { public static NumberFormatter getIntegerFormatter() { + return getIntegerFormatter(0, Integer.MAX_VALUE); + } + + public static NumberFormatter getIntegerFormatter(int minValue, int maxValue) { NumberFormat format = NumberFormat.getInstance(); NumberFormatter formatter = new NumberFormatter(format); formatter.setValueClass(Integer.class); - formatter.setMinimum(0); - formatter.setMaximum(Integer.MAX_VALUE); + formatter.setMinimum(minValue); + formatter.setMaximum(maxValue); formatter.setCommitsOnValidEdit(true); return formatter; @@ -29,4 +33,5 @@ public class FormatHelper { return formatter; } + } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/IntegerInputField.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/IntegerInputField.java index fe400a1..09d40d6 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/IntegerInputField.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/IntegerInputField.java @@ -8,12 +8,17 @@ import javax.swing.JFormattedTextField; @SuppressWarnings("serial") public class IntegerInputField extends JFormattedTextField{ + public IntegerInputField(int minValue, int maxValue) { + super(FormatHelper.getIntegerFormatter(minValue,maxValue)); + this.setColumns(8); + } + public IntegerInputField() { super(FormatHelper.getIntegerFormatter()); - this.setColumns(8); + this.setColumns(8); } - public int getTimeLimit() { + public int getValueAsInt() { return Integer.parseInt(getText()); } } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/MainPanel.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/MainPanel.java index d4c28ab..bdabdfb 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/MainPanel.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/MainPanel.java @@ -16,11 +16,13 @@ import org.cytoscape.application.swing.CytoPanelComponent; import org.cytoscape.application.swing.CytoPanelName; import org.cytoscape.work.AbstractTask; import org.cytoscape.work.TaskIterator; +import org.slf4j.Logger; import de.hhu.ba.yoshikoWrapper.core.AlgorithmTask; import de.hhu.ba.yoshikoWrapper.core.CyCore; import de.hhu.ba.yoshikoWrapper.core.LocalizationManager; import de.hhu.ba.yoshikoWrapper.core.YoshikoLoader; +import de.hhu.ba.yoshikoWrapper.logging.YoshikoLogger; import de.hhu.ba.yoshikoWrapper.swig.LibraryInterface; /**This class describes the Swing Panel that the user interacts with in cytoscape @@ -45,12 +47,15 @@ public class MainPanel extends ComfortPanel implements CytoPanelComponent { private final ReductionRulesChooser reductionRulesChooser; - private final JCheckBox useTriangleCutsBox; private final JCheckBox usePartitionCutsBox; + + private final SolutionNumberChooser solutionNumberChooser; + //SYMBOLIC LINKS private final SolutionsPanel solutionsPanel; + private final Logger logger = YoshikoLogger.getInstance().getLogger(); /** * Main constructor, creates a new Panel and initializes subcomponents @@ -72,21 +77,25 @@ public class MainPanel extends ComfortPanel implements CytoPanelComponent { heuristicGroup = new ButtonGroup(); useILP = new JRadioButton("Use Integer Linear Programming"); useILP.setSelected(true); + useHeuristic = new JRadioButton("Use Heuristic"); heuristicGroup.add(useILP); heuristicGroup.add(useHeuristic); - + solutionNumberChooser = new SolutionNumberChooser(); + reductionRulesChooser = new ReductionRulesChooser(); timeLimitSetter = new TimeLimitSetter(); useTriangleCutsBox = new JCheckBox("Use Triangle Cuts"); usePartitionCutsBox = new JCheckBox("Use Partition Cuts"); - JButton runButton = new JButton("RUN"); runButton.addActionListener(buttonListener); + //Link time limit option to ILP + useILP.addActionListener(ilpHeuristicSwitch); + useHeuristic.addActionListener(ilpHeuristicSwitch); this.addAll( langSwitcher, @@ -98,6 +107,7 @@ public class MainPanel extends ComfortPanel implements CytoPanelComponent { reductionRulesChooser, useTriangleCutsBox, usePartitionCutsBox, + solutionNumberChooser, runButton ); @@ -141,13 +151,16 @@ public class MainPanel extends ComfortPanel implements CytoPanelComponent { useTriangleCutsBox.isSelected(), usePartitionCutsBox.isSelected(), useHeuristic.isSelected(), + solutionNumberChooser.getSolCount(), solutionsPanel ); CyCore.dialogTaskManager.execute(new TaskIterator(1,yoshiko)); solutionsPanel.setVisible(true); + } else { JOptionPane.showMessageDialog( + null, LocalizationManager.get("noLibTitle"), LocalizationManager.get("noLibMessage"), @@ -157,6 +170,18 @@ public class MainPanel extends ComfortPanel implements CytoPanelComponent { } }; + ActionListener ilpHeuristicSwitch = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (useILP.isSelected()) { + timeLimitSetter.setEnabled(true); + } + else { + timeLimitSetter.setEnabled(false); + } + } + }; + //GETTER / SETTER diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionNumberChooser.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionNumberChooser.java new file mode 100644 index 0000000..dc90480 --- /dev/null +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionNumberChooser.java @@ -0,0 +1,26 @@ +package de.hhu.ba.yoshikoWrapper.gui; + +import javax.swing.JLabel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +import de.hhu.ba.yoshikoWrapper.core.LocalizationManager; + +@SuppressWarnings("serial") +public class SolutionNumberChooser extends ComfortPanel { + private final JSpinner numSolutionsSetter; + private final JLabel label; + + public SolutionNumberChooser() { + //Swing Component init + numSolutionsSetter = new JSpinner(); + numSolutionsSetter.setModel(new SpinnerNumberModel(1,1,Integer.MAX_VALUE,1)); + label = new JLabel(LocalizationManager.get("nrSolutions")); + this.addAll(label, numSolutionsSetter); + + } + + public int getSolCount() { + return (int)numSolutionsSetter.getValue(); + } +} diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionsPanel.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionsPanel.java index 778c694..cb6373e 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionsPanel.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/SolutionsPanel.java @@ -4,6 +4,7 @@ import java.awt.Component; import javax.swing.BoxLayout; import javax.swing.Icon; +import javax.swing.JLabel; import javax.swing.JTabbedPane; import org.cytoscape.application.swing.CytoPanelComponent; @@ -15,11 +16,13 @@ import de.hhu.ba.yoshikoWrapper.core.LocalizationManager; public class SolutionsPanel extends ComfortPanel implements CytoPanelComponent{ private JTabbedPane solutionTabs; + private JLabel costLabel; public SolutionsPanel() { this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS)); solutionTabs = new JTabbedPane(); - this.add(solutionTabs); + costLabel = new JLabel("COST"); + this.addAll(costLabel,solutionTabs); } public SolutionTab addSolutionTab(long i) { @@ -31,6 +34,10 @@ public class SolutionsPanel extends ComfortPanel implements CytoPanelComponent{ return tab; } + public void setCost(double modificationCost) { + costLabel.setText(LocalizationManager.get("cost")+" "+modificationCost); + } + public void reset() { solutionTabs.removeAll(); } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/TimeLimitSetter.java b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/TimeLimitSetter.java index c5445d6..993afbb 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/gui/TimeLimitSetter.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/gui/TimeLimitSetter.java @@ -5,6 +5,8 @@ import java.awt.event.ActionListener; import javax.swing.JCheckBox; +import de.hhu.ba.yoshikoWrapper.core.LocalizationManager; + @SuppressWarnings("serial") public class TimeLimitSetter extends ComfortPanel{ @@ -12,8 +14,9 @@ public class TimeLimitSetter extends ComfortPanel{ private IntegerInputField numberField; public TimeLimitSetter() { - checkBox = new JCheckBox("Use time limit (s):"); + checkBox = new JCheckBox(LocalizationManager.get("timeLimitILP")); numberField = new IntegerInputField(); + numberField.setText("60"); numberField.setEnabled(false); //By default time limit is turned off checkBox.addActionListener( new ActionListener() { @@ -29,11 +32,22 @@ public class TimeLimitSetter extends ComfortPanel{ this.addAll(checkBox,numberField); } + public void setEnabled(boolean enabled) { + if (enabled) { + this.checkBox.setEnabled(enabled); + this.numberField.setEnabled(this.checkBox.isSelected()); + } + else { + this.checkBox.setEnabled(enabled); + this.numberField.setEnabled(enabled); + } + } + public int getTimeLimit() { if (!checkBox.isSelected()) { return -1; } - return numberField.getTimeLimit(); + return numberField.getValueAsInt(); } } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/swig/LibraryInterface.java b/src/main/java/de/hhu/ba/yoshikoWrapper/swig/LibraryInterface.java index f742a24..273cc97 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/swig/LibraryInterface.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/swig/LibraryInterface.java @@ -80,6 +80,10 @@ public class LibraryInterface { return LibraryInterfaceJNI.ClusterEditingSolutions_getTotalCost(SWIGTYPE_p_ysk__ClusterEditingSolutions.getCPtr(self)); } + public static boolean ClusterEditingSolutions_isTimedOut(SWIGTYPE_p_ysk__ClusterEditingSolutions self) { + return LibraryInterfaceJNI.ClusterEditingSolutions_isTimedOut(SWIGTYPE_p_ysk__ClusterEditingSolutions.getCPtr(self)); + } + public static void delete_ClusterEditingSolutions(SWIGTYPE_p_ysk__ClusterEditingSolutions self) { LibraryInterfaceJNI.delete_ClusterEditingSolutions(SWIGTYPE_p_ysk__ClusterEditingSolutions.getCPtr(self)); } @@ -113,8 +117,8 @@ public class LibraryInterface { return LibraryInterfaceJNI.getVersionString(); } - public static SWIGTYPE_p_ysk__ClusterEditingSolutions processLibraryInput(SWIGTYPE_p_yskInput__LibraryInput libIn, int nrOptimalSolutions, String rulesBitMask, double multiplicativeFactor, boolean useHeuristic, boolean separatePartitionCuts, boolean separateTriangles) { - long cPtr = LibraryInterfaceJNI.processLibraryInput(SWIGTYPE_p_yskInput__LibraryInput.getCPtr(libIn), nrOptimalSolutions, rulesBitMask, multiplicativeFactor, useHeuristic, separatePartitionCuts, separateTriangles); + public static SWIGTYPE_p_ysk__ClusterEditingSolutions processLibraryInput(SWIGTYPE_p_yskInput__LibraryInput libIn, int nrOptimalSolutions, String rulesBitMask, double multiplicativeFactor, boolean separatePartitionCuts, boolean separateTriangles, boolean useHeuristic) { + long cPtr = LibraryInterfaceJNI.processLibraryInput(SWIGTYPE_p_yskInput__LibraryInput.getCPtr(libIn), nrOptimalSolutions, rulesBitMask, multiplicativeFactor, separatePartitionCuts, separateTriangles, useHeuristic); return (cPtr == 0) ? null : new SWIGTYPE_p_ysk__ClusterEditingSolutions(cPtr, false); } @@ -122,4 +126,8 @@ public class LibraryInterface { LibraryInterfaceJNI.setTimeLimit(limit); } + public static void setVerbosity(int level) { + LibraryInterfaceJNI.setVerbosity(level); + } + } diff --git a/src/main/java/de/hhu/ba/yoshikoWrapper/swig/LibraryInterfaceJNI.java b/src/main/java/de/hhu/ba/yoshikoWrapper/swig/LibraryInterfaceJNI.java index 7eeb8c9..3870b0d 100644 --- a/src/main/java/de/hhu/ba/yoshikoWrapper/swig/LibraryInterfaceJNI.java +++ b/src/main/java/de/hhu/ba/yoshikoWrapper/swig/LibraryInterfaceJNI.java @@ -26,6 +26,7 @@ public class LibraryInterfaceJNI { public final static native long ClusterEditingSolutions_getSolution(long jarg1, long jarg2); public final static native long ClusterEditingSolutions_getNumberOfSolutions(long jarg1); public final static native double ClusterEditingSolutions_getTotalCost(long jarg1); + public final static native boolean ClusterEditingSolutions_isTimedOut(long jarg1); public final static native void delete_ClusterEditingSolutions(long jarg1); public final static native long new_LibraryInput(); public final static native void delete_LibraryInput(long jarg1); @@ -36,4 +37,5 @@ public class LibraryInterfaceJNI { public final static native String getVersionString(); public final static native long processLibraryInput(long jarg1, int jarg2, String jarg3, double jarg4, boolean jarg5, boolean jarg6, boolean jarg7); public final static native void setTimeLimit(int jarg1); + public final static native void setVerbosity(int jarg1); } diff --git a/src/main/resources/YoshikoStrings.properties b/src/main/resources/YoshikoStrings.properties index 6b0a86b..a6b05e6 100644 --- a/src/main/resources/YoshikoStrings.properties +++ b/src/main/resources/YoshikoStrings.properties @@ -12,4 +12,9 @@ multFactor = Multiplicative Factor for SNR: paidCost = Paid a total modification cost of: clusterFound = Clusters found: overrideSolution = Running Yoshiko will override previous solutions. Continue? -warning = Warning \ No newline at end of file +warning = Warning +timeLimitILP = Use time limit for ILP (s): +timedOutTitle = Timeout +timedOutMessage = The ILP exceeded the time-limit! +cost = Cost: +nrSolutions = Number of Solutions: \ No newline at end of file -- GitLab