Commit 3ae8a0a3 authored by Philipp Spohr's avatar Philipp Spohr
Browse files

-Improved Meta-Graph performance

-Fixed bug using ILP when selecting heuristic mode
-Fixed bug with discarding solution sometimes not removing subgraphs/metagraph
-Fixed bug with infinite gap values being formatted incorrectly
-Enabled highlighting of clusters in meta-graph
-Enabled returning to original network view upon result destruction
-Fixed bugs with cluster-view sometimes using incorrect styles/layout
-Reworked concurrency / synchronization
-Various smaller performance issues
parent 740d75e6
......@@ -33,7 +33,7 @@
<groupId>de.hhu.ba</groupId>
<artifactId>yoshikoWrapper</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
<name>YoshikoWrapper</name>
......
......@@ -21,6 +21,8 @@
******************************************************************************/
package de.hhu.ba.yoshikoWrapper.core;
import java.util.concurrent.CountDownLatch;
import org.cytoscape.application.CyApplicationManager;
import org.cytoscape.application.swing.CySwingApplication;
import org.cytoscape.model.CyNetwork;
......@@ -36,6 +38,10 @@ import org.cytoscape.view.presentation.RenderingEngineFactory;
import org.cytoscape.view.vizmap.VisualMappingFunctionFactory;
import org.cytoscape.view.vizmap.VisualMappingManager;
import org.cytoscape.view.vizmap.VisualStyleFactory;
import org.cytoscape.work.FinishStatus;
import org.cytoscape.work.ObservableTask;
import org.cytoscape.work.TaskIterator;
import org.cytoscape.work.TaskObserver;
import org.cytoscape.work.swing.DialogTaskManager;
import org.osgi.framework.BundleContext;
......@@ -68,4 +74,25 @@ public class CyCore {
public static String getConfig(String key) {
return cm.getProperties().getProperty(key);
}
/**
* Convenience function that runs all tasks in a task iterator but blocks until all tasks are finished
* @param taskIterator
* @throws InterruptedException
*/
public static synchronized void runAndWait(TaskIterator taskIterator) throws InterruptedException {
CountDownLatch blockLatch = new CountDownLatch(1);
dialogTaskManager.execute(taskIterator,new TaskObserver() {
@Override
public void taskFinished(ObservableTask task) {}
@Override
public void allFinished(FinishStatus finishStatus) {
blockLatch.countDown();
}
});
blockLatch.await();
}
}
......@@ -44,7 +44,9 @@ public class StatusInformer extends CplexInformer {
@Override
public void updateStatus(YoshikoState state, double value) {
if (state == YoshikoState.SOLVING_ILP){
taskMonitor.setStatusMessage(LocalizationManager.get("currentGap")+": "+SwingUtil.twoDecimals.format(value)+"%");
if (value <= 1.0) {
taskMonitor.setStatusMessage(LocalizationManager.get("currentGap")+": "+SwingUtil.twoDecimals.format(value)+"%");
}
}
}
......
package de.hhu.ba.yoshikoWrapper.core;
import org.osgi.framework.Version;
public class YoshUtil {
......
......@@ -28,7 +28,6 @@ import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import org.cytoscape.model.CyEdge;
import org.cytoscape.model.CyNetwork;
......@@ -39,9 +38,10 @@ import org.cytoscape.model.subnetwork.CySubNetwork;
import org.cytoscape.view.layout.CyLayoutAlgorithm;
import org.cytoscape.view.model.CyNetworkView;
import org.cytoscape.view.presentation.RenderingEngine;
import org.cytoscape.work.Task;
import org.cytoscape.work.FinishStatus;
import org.cytoscape.work.ObservableTask;
import org.cytoscape.work.TaskIterator;
import org.cytoscape.work.TaskMonitor;
import org.cytoscape.work.TaskObserver;
import org.slf4j.Logger;
import de.hhu.ba.yoshikoWrapper.core.CyCore;
......@@ -61,6 +61,9 @@ public class YoshikoCluster {
private Image img;
private CySubNetwork subnet;
//SYMBOLIC LINKS
private final YoshikoSolution solution;
private Logger logger = YoshikoLogger.getInstance().getLogger();
......@@ -90,43 +93,54 @@ public class YoshikoCluster {
}
/**
* Generates a subgraph for this cluster by choosing the nodes and induced edges from the original graph
* Generates a subgraph for this clusters by choosing the nodes and induced edges from the original graph if such a graph doesn't exist yet.
* @return
*/
public CySubNetwork getSubNetwork() {
CyRootNetwork originalGraphAsRoot =
CyCore.rootNetworkManager.getRootNetwork(solution.getOriginalGraph());
//Create nested graph and cluster subnet
ArrayList<CyEdge> inducedEdges = new ArrayList<CyEdge>();
for (CyNode n: nodes) {
//Sadly Cytoscape doesnt provide a comfort function here
List<CyEdge> adjacentEdges = solution.getOriginalGraph().getAdjacentEdgeList(n, CyEdge.Type.ANY);
for (CyEdge e: adjacentEdges) {
if (nodes.contains(e.getSource()) && nodes.contains(e.getTarget())) {
inducedEdges.add(e);
if (subnet == null) {
CyRootNetwork originalGraphAsRoot =
CyCore.rootNetworkManager.getRootNetwork(solution.getOriginalGraph());
//Create nested graph and clusters subnet
ArrayList<CyEdge> inducedEdges = new ArrayList<CyEdge>();
for (CyNode n: nodes) {
//Sadly Cytoscape doesnt provide a comfort function here
List<CyEdge> adjacentEdges = solution.getOriginalGraph().getAdjacentEdgeList(n, CyEdge.Type.ANY);
for (CyEdge e: adjacentEdges) {
if (nodes.contains(e.getSource()) && nodes.contains(e.getTarget())) {
inducedEdges.add(e);
}
}
}
}
CySubNetwork subnet = originalGraphAsRoot.addSubNetwork(nodes ,inducedEdges);
subnet.getRow(subnet).set(CyNetwork.NAME, LocalizationManager.get("cluster")+" "+(id+1));
subnet = originalGraphAsRoot.addSubNetwork(nodes ,inducedEdges);
subnet.getRow(subnet).set(CyNetwork.NAME, LocalizationManager.get("clusters")+" "+(id+1));
}
return subnet;
}
public void highlight() {
if (CyCore.cy.getCurrentNetwork() == solution.getOriginalGraph()) {
highlightInOriginalGraph();
}
else if (CyCore.cy.getCurrentNetwork() == solution.getMetaGraph()) {
solution.highlightInMetaGraph(this);
}
}
/**
* Attempt to select the nodes belonging to this cluster in the original Graph given that they still exist
* Attempt to select the nodes belonging to this clusters in the original Graph given that they still exist
*/
public void highlightInOriginalGraph() {
private void highlightInOriginalGraph() {
try {
List<CyRow> allRows = solution.getOriginalGraph().getDefaultNodeTable().getAllRows();
for (CyRow r: allRows) {
r.set("selected", false);
}
//Select nodes corresponding to the cluster
//Select nodes corresponding to the clusters
for (CyNode n : nodes) {
solution.getOriginalGraph().getRow(n).set("selected", true);
}
......@@ -136,67 +150,38 @@ public class YoshikoCluster {
}
}
public void applyImage(JLabel label, int width, int height) throws Exception {
if (img != null) {
label.setIcon(new ImageIcon(img));
}
else {
getImage(width,height,label);
}
}
private void getImage(int width, int height,JLabel label) {
public void generateClusterIcon(int width, int height,JLabel label) throws InterruptedException {
final CyNetworkView view = CyCore.networkViewFactory.createNetworkView(getSubNetwork());
//layout cluster
//layout clusters
final CyLayoutAlgorithm layout = CyCore.layoutAlgorithmManager.getDefaultLayout();
final TaskIterator createLayout = layout.createTaskIterator(
CyCore.runAndWait(layout.createTaskIterator(
view,
layout.getDefaultLayoutContext(),
CyLayoutAlgorithm.ALL_NODE_VIEWS,
null
)
);
createLayout.append(
new Task() {
@Override
public void run(TaskMonitor taskMonitor) throws Exception {
taskMonitor.setStatusMessage("Generating cluster view for C:"+id);
view.setVisualProperty(NETWORK_WIDTH, new Double(width));
view.setVisualProperty(NETWORK_HEIGHT, new Double(height));
view.fitContent();
view.setVisualProperty(NETWORK_WIDTH, new Double(width));
view.setVisualProperty(NETWORK_HEIGHT, new Double(height));
view.fitContent();
StyleManager.style(view, CyCore.visualMappingManager.getCurrentVisualStyle());
StyleManager.style(view, CyCore.visualMappingManager.getCurrentVisualStyle());
RenderingEngine<CyNetwork> renderingEngine = CyCore.renderingEngineFactory.createRenderingEngine(label, view);
SwingUtilities.invokeLater(new Runnable() {
RenderingEngine<CyNetwork> renderingEngine = CyCore.renderingEngineFactory.createRenderingEngine(label, view);
@Override
public void run() {
img = renderingEngine.createImage(width,height);
label.setIcon(new ImageIcon(img));
renderingEngine.dispose();
view.dispose();
}
});
}
@Override
public void cancel() {}
img = renderingEngine.createImage(width,height);
label.setIcon(new ImageIcon(img));
}
);
renderingEngine.dispose();
view.dispose();
}
CyCore.dialogTaskManager.execute(
createLayout
);
public void delete() {
if (subnet != null) {
CyCore.networkManager.destroyNetwork(subnet);
}
}
public int getSize() {
......@@ -215,4 +200,8 @@ public class YoshikoCluster {
return solution.getOriginalGraph().getRow(n).get("name", String.class);
}
}
......@@ -71,5 +71,11 @@ public class YoshikoResult {
return originalGraph;
}
public void delete() {
for (YoshikoSolution s: solutions) {
s.delete();
}
}
}
......@@ -22,19 +22,36 @@
package de.hhu.ba.yoshikoWrapper.graphModel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.swing.JOptionPane;
import org.cytoscape.model.CyNetwork;
import org.cytoscape.model.CyNode;
import org.cytoscape.model.CyRow;
import org.slf4j.Logger;
import de.hhu.ba.yoshikoWrapper.core.CyCore;
import de.hhu.ba.yoshikoWrapper.logging.YoshikoLogger;
public class YoshikoSolution {
private final YoshikoResult result;
public ArrayList<YoshikoCluster> cluster;
private CyNetwork metaGraph;
private HashMap<YoshikoCluster, CyNode> metaGraphMap;
public ArrayList<YoshikoCluster> clusters;
private final long id;
private Logger logger = YoshikoLogger.getInstance().getLogger();
public YoshikoSolution(YoshikoResult yoshikoResult, long id) {
cluster = new ArrayList<YoshikoCluster>();
clusters = new ArrayList<YoshikoCluster>();
this.result = yoshikoResult;
this.id = id;
}
......@@ -42,7 +59,7 @@ public class YoshikoSolution {
//_____________GETTER / SETTER ________________//
public ArrayList<YoshikoCluster> getClusters() {
return cluster;
return clusters;
}
/**
......@@ -56,4 +73,37 @@ public class YoshikoSolution {
return result.getOriginalGraph();
}
public void delete() {
for (YoshikoCluster c: clusters) {
c.delete();
}
if (this.metaGraph != null) {
CyCore.networkManager.destroyNetwork(metaGraph);
}
}
public void setMetaGraph(CyNetwork metaGraph, HashMap<YoshikoCluster, CyNode> map) {
this.metaGraph = metaGraph;
this.metaGraphMap = map;
}
public CyNetwork getMetaGraph() {
return metaGraph;
}
public void highlightInMetaGraph(YoshikoCluster yoshikoCluster) {
try {
List<CyRow> allRows = metaGraph.getDefaultNodeTable().getAllRows();
for (CyRow r: allRows) {
r.set("selected", false);
}
metaGraph.getRow(metaGraphMap.get(yoshikoCluster)).set("selected", true);
}
catch (Exception e) {
logger.warn("The graph doesn't exist anymore, can't highlight nodes!");
}
}
}
......@@ -42,6 +42,7 @@ import de.hhu.ba.yoshikoWrapper.core.LocalizationManager;
import de.hhu.ba.yoshikoWrapper.graphModel.YoshikoCluster;
import de.hhu.ba.yoshikoWrapper.swing.GraphicsLoader;
import de.hhu.ba.yoshikoWrapper.swing.SwingUtil;
import de.hhu.ba.yoshikoWrapper.tasks.AlgorithmTask;
@SuppressWarnings("serial")
public class ClusterView extends JPanel {
......@@ -76,17 +77,17 @@ public class ClusterView extends JPanel {
//Swing init
title = new JLabel(LocalizationManager.get("cluster")+" "+(c.getID()+1));
title = new JLabel(LocalizationManager.get("clusters")+" "+(c.getID()+1));
clusterSize = new JLabel(LocalizationManager.get("clusterSize")+" "+c.getSize());
icon = new JLabel();
//icon.setBorder(BorderFactory.createLineBorder(Color.BLACK));
cluster.applyImage(icon,CLUSTER_ICON_SIZE, CLUSTER_ICON_SIZE);
cluster.generateClusterIcon(CLUSTER_ICON_SIZE, CLUSTER_ICON_SIZE,icon);
SwingUtil.addAll(this,title,clusterSize,icon);
nodeList = new BasicCollapsiblePanel(LocalizationManager.get("nodes"));
//Loop over nodes in the cluster and add them to the view
//Loop over nodes in the clusters and add them to the view
for (CyNode n : c.getSubNetwork().getNodeList()) {
nodeList.add(
new JLabel(
......@@ -147,7 +148,7 @@ public class ClusterView extends JPanel {
@Override
public void mouseEntered(MouseEvent e) {
cluster.highlightInOriginalGraph();
cluster.highlight();
setBorder(isSelected ? selectedBorder : highlightBorder);
}
......
......@@ -25,9 +25,11 @@ import static javax.swing.GroupLayout.*;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Properties;
import javax.swing.BoxLayout;
......@@ -58,6 +60,7 @@ import org.cytoscape.model.events.AddedNodesListener;
import org.cytoscape.model.events.NetworkAboutToBeDestroyedEvent;
import org.cytoscape.model.events.NetworkAboutToBeDestroyedListener;
import org.cytoscape.util.swing.BasicCollapsiblePanel;
import org.cytoscape.view.model.CyNetworkView;
import de.hhu.ba.yoshikoWrapper.core.CyCore;
import de.hhu.ba.yoshikoWrapper.core.LocalizationManager;
......@@ -123,11 +126,16 @@ NetworkAboutToBeDestroyedListener
solutionTabs.add(tab);
}
marker = new BasicCollapsiblePanel(LocalizationManager.get("solutionMarker"));
marker.setLayout(new BoxLayout(marker,BoxLayout.Y_AXIS));
JLabel costLabel = new JLabel(LocalizationManager.get("cost")+" "+result.getFlags().getTotalCost());
marker.add(costLabel);
if (result.getFlags().getIlpGenerated()) {
//TODO: Move to MarkerPanel for better codestyle
//Optional Markers
marker = new BasicCollapsiblePanel(LocalizationManager.get("ilpMarker"));
marker.setLayout(new BoxLayout(marker,BoxLayout.Y_AXIS));
if(result.getFlags().getOptimal()) {
JLabel optimalLabel;
optimalLabel = new JLabel(LocalizationManager.get("optimal"));
......@@ -142,15 +150,15 @@ NetworkAboutToBeDestroyedListener
marker.add(new JLabel(result.getFlags().getSolvedInstances()+"/"+result.getFlags().getReducedInstances()+" "+LocalizationManager.get("redSolved")));
marker.add(new JLabel(LocalizationManager.get("lastInstanceGap")+" "+(int)(100*result.getFlags().getLastGap())+"%"));
}
JLabel costLabel = new JLabel(LocalizationManager.get("cost")+" "+result.getFlags().getTotalCost());
marker.add(costLabel);
if (result.getFlags().getTimedOut()) {
marker.add(new JLabel(LocalizationManager.get("timeoutMarker")));
}
marker.setCollapsed(false);
this.add(marker);
}
this.add(marker);
destroyButton = new JButton(LocalizationManager.get("discardSolution"));
destroyButton.addActionListener(new ActionListener() {
......@@ -172,16 +180,13 @@ NetworkAboutToBeDestroyedListener
layout.setHorizontalGroup(horizontalGroup);
layout.setVerticalGroup(verticalGroup);
if (result.getFlags().getIlpGenerated()) {
horizontalGroup.addComponent(marker,DEFAULT_SIZE,DEFAULT_SIZE,DEFAULT_SIZE);
verticalGroup.addComponent(marker,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE);
}
horizontalGroup
.addComponent(marker,DEFAULT_SIZE,DEFAULT_SIZE,DEFAULT_SIZE)
.addComponent(invalidLabel,DEFAULT_SIZE, PREFERRED_SIZE,Short.MAX_VALUE)
.addComponent(tabbedPane,HACKFIX_FIXED_WIDTH, PREFERRED_SIZE,Short.MAX_VALUE)
.addComponent(destroyButton,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE);
verticalGroup
.addComponent(marker,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
.addComponent(invalidLabel,DEFAULT_SIZE, DEFAULT_SIZE,DEFAULT_SIZE)
.addComponent(tabbedPane,DEFAULT_SIZE, DEFAULT_SIZE,PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, DEFAULT_SIZE, Short.MAX_VALUE)
......@@ -190,6 +195,8 @@ NetworkAboutToBeDestroyedListener
layout.setAutoCreateGaps(true);
layout.setAutoCreateContainerGaps(true);
//SWING BLACK MAGIC FOR ADEPTS
this.setMinimumSize(new Dimension(HACKFIX_FIXED_WIDTH,this.getMinimumSize().height));
this.setLayout(layout);
......@@ -206,6 +213,7 @@ NetworkAboutToBeDestroyedListener
}
public void deleteSolution() {
int dialogResult = JOptionPane.showConfirmDialog (
null,
LocalizationManager.get("deleteSolution"),
......@@ -215,9 +223,19 @@ NetworkAboutToBeDestroyedListener
if (dialogResult != JOptionPane.YES_OPTION) {
return;
}
//Restore view
if (result.getOriginalGraph() != null) {
Collection<CyNetworkView> viewsToReturn = CyCore.networkViewManager.getNetworkViews(result.getOriginalGraph());
if (!viewsToReturn.isEmpty()) {
CyCore.cy.setCurrentNetworkView(viewsToReturn.iterator().next());
}
}
CyCore.registrar.unregisterService(this,CytoPanelComponent.class);
removeAll();
result.delete();
super.setVisible(false);
}
private void invalidateResult() {
......
......@@ -86,14 +86,14 @@ public class SolutionTab extends JPanel {
//Declaration of Swing Components
clusterViewList = new ClusterViewList();
for (YoshikoCluster c: solution.cluster) {
for (YoshikoCluster c: solution.clusters) {
ClusterView clusterView = new ClusterView(c);
clusterViewList.add(clusterView);
}
scrollPane = new JScrollPane(clusterViewList);
clusterCount = new JLabel(LocalizationManager.get("clusterFound")+" "+s.cluster.size());
clusterCount = new JLabel(LocalizationManager.get("clusterFound")+" "+s.clusters.size());
createClusterView = new JButton(LocalizationManager.get("createClusterView"));
createMetaGraph = new JButton(LocalizationManager.get("createMetaGraph"));
......@@ -170,7 +170,7 @@ public class SolutionTab extends JPanel {
.addGap(8)
.addComponent(clusterCount,DEFAULT_SIZE,DEFAULT_SIZE,DEFAULT_SIZE)
.addGap(8)
.addComponent(scrollPane,PREFERRED_SIZE,DEFAULT_SIZE,Short.MAX_VALUE)
.addComponent(scrollPane,DEFAULT_SIZE,DEFAULT_SIZE,Short.MAX_VALUE)
.addComponent(createClusterView,DEFAULT_SIZE,DEFAULT_SIZE,DEFAULT_SIZE)
.addComponent(createMetaGraph,DEFAULT_SIZE,DEFAULT_SIZE,DEFAULT_SIZE)
);
......
......@@ -71,7 +71,7 @@ public class AlgorithmTask extends AbstractTask {
private ResultPanel resultPanel;
public AlgorithmTask(// <<< Too many variables here, some should be grouped later TODO:
public AlgorithmTask(
Window statusWindow,
CyNetwork net,
ParameterSet parameterSet
......@@ -85,6 +85,7 @@ public class AlgorithmTask extends AbstractTask {
@Override
public void run(TaskMonitor taskMonitor) throws Exception {
//TODO: Improve setProgress values
taskMonitor.setTitle(LocalizationManager.get("yoshTask"));
taskMonitor.setProgress(0.0);
......@@ -127,9 +128,9 @@ public class AlgorithmTask extends AbstractTask {
parameterSet.solCount,
parameterSet.reductionRulesBitMask,
parameterSet.snrMultFactor,
parameterSet.useHeuristic,
parameterSet.usePartitionCuts,
parameterSet.useTriangleCuts,
parameterSet.useHeuristic
parameterSet.useTriangleCuts
);
......@@ -162,30 +163,30 @@ public class AlgorithmTask extends AbstractTask {
//Fetch number of clusters in the solution
long numberOfClusters = result.getNumberOfClusters(i);
//Loop over cluster
//Loop over clusters
for (long k=0;k<numberOfClusters;k++) {
//Create java instance
YoshikoCluster cluster = new YoshikoCluster(solution,k);
taskMonitor.setStatusMessage("Processing cluster "+(k+1)+" of "+numberOfClusters);
taskMonitor.setStatusMessage("Processing clusters "+(k+1)+" of "+numberOfClusters);