Commit de17a6ef authored by Philipp Spohr's avatar Philipp Spohr
Browse files

Some work on invalidating a result upon change in the original graph

parent 0e76383d
......@@ -23,6 +23,7 @@ package de.hhu.ba.yoshikoWrapper.graphModel;
import java.awt.Image;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import javax.swing.ImageIcon;
......@@ -57,41 +58,63 @@ public class YoshikoCluster {
private final long id;
private ArrayList<CyNode> nodes;
private CySubNetwork net;
private Image img;
//SYMBOLIC LINKS
private final CyNetwork originalGraph;
private final YoshikoSolution solution;
private Logger logger = YoshikoLogger.getInstance().getLogger();
//STATICS
public YoshikoCluster(long id, CyNetwork originalGraph) {
public static Comparator<YoshikoCluster> lessThanComparator = new Comparator<YoshikoCluster>() {
@Override
public int compare(YoshikoCluster o1, YoshikoCluster o2) {
if (o1.getSize() == o2.getSize()) {
return 0;
}
else if(o1.getSize() < o2.getSize()) {
return 1;
}
return -1;
}
};
public YoshikoCluster(YoshikoSolution solution, long id) {
this.id = id;
this.originalGraph = originalGraph;
this.solution = solution;
this.nodes = new ArrayList<CyNode>();
}
public void createSubNetwork() {
/**
* Generates a subgraph for this cluster by choosing the nodes and induced edges from the original graph
* @return
*/
public CySubNetwork getSubNetwork() {
CyRootNetwork originalGraphAsRoot = CyCore.rootNetworkManager.getRootNetwork(originalGraph);
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 = originalGraph.getAdjacentEdgeList(n, CyEdge.Type.ANY);
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));
net = subnet; //Save for further reference
return subnet;
}
/**
......@@ -99,13 +122,13 @@ public class YoshikoCluster {
*/
public void highlightInOriginalGraph() {
try {
List<CyRow> allRows = originalGraph.getDefaultNodeTable().getAllRows();
List<CyRow> allRows = solution.getOriginalGraph().getDefaultNodeTable().getAllRows();
for (CyRow r: allRows) {
r.set("selected", false);
}
//Select nodes corresponding to the cluster
for (CyNode n : nodes) {
originalGraph.getRow(n).set("selected", true);
solution.getOriginalGraph().getRow(n).set("selected", true);
}
}
catch (Exception e) {
......@@ -116,10 +139,6 @@ public class YoshikoCluster {
public void applyImage(JLabel label, int width, int height) throws Exception {
if (net == null) {
throw new Exception("Can't have an image without having a network associated");
}
if (img != null) {
label.setIcon(new ImageIcon(img));
}
......@@ -129,7 +148,7 @@ public class YoshikoCluster {
}
private void getImage(int width, int height,JLabel label) {
final CyNetworkView view = CyCore.networkViewFactory.createNetworkView(net);
final CyNetworkView view = CyCore.networkViewFactory.createNetworkView(getSubNetwork());
//layout cluster
final CyLayoutAlgorithm layout = CyCore.layoutAlgorithmManager.getDefaultLayout();
......@@ -188,16 +207,12 @@ public class YoshikoCluster {
return id;
}
public CySubNetwork getSubNetwork() {
return net;
}
public void addNode(CyNode node) {
nodes.add(node);
}
public String getNodeName(CyNode n) {
return originalGraph.getRow(n).get("name", String.class);
return solution.getOriginalGraph().getRow(n).get("name", String.class);
}
}
/*******************************************************************************
* Copyright (C) 2017 Philipp Spohr
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
......@@ -23,22 +23,59 @@ package de.hhu.ba.yoshikoWrapper.graphModel;
import java.util.ArrayList;
import org.cytoscape.model.CyNetwork;
import de.hhu.ba.yoshikoWrapper.swig.SolutionFlags;
/**Basic data class that represents a CES instance internally. By using this class the C++ resources can be freed upon retrieval.
*
*
*/
public class YoshikoResult {
public ArrayList<YoshikoSolution> solutions;
public SolutionFlags flags;
public YoshikoResult() {
private CyNetwork originalGraph;
private ArrayList<YoshikoSolution> solutions;
private SolutionFlags flags;
public YoshikoResult(CyNetwork net, SolutionFlags flags) {
solutions = new ArrayList<YoshikoSolution>();
}
this.originalGraph = net;
this.flags = flags;
}
public void dispose() {
flags.delete();
originalGraph.dispose();
}
//___________SETTER GETTER_____________//
/**
* @return the flags asspciated with this result
*/
public SolutionFlags getFlags() {
return flags;
}
public void addSolution(YoshikoSolution solution) {
solutions.add(solution);
}
public ArrayList<YoshikoSolution> getSolutions() {
return solutions;
}
public CyNetwork getOriginalGraph() {
return originalGraph;
}
}
......@@ -22,52 +22,29 @@
package de.hhu.ba.yoshikoWrapper.graphModel;
import java.util.ArrayList;
import java.util.HashMap;
import org.cytoscape.model.CyEdge;
import org.cytoscape.model.CyNetwork;
import org.cytoscape.model.CyNode;
import org.cytoscape.model.CyEdge.Type;
import org.cytoscape.model.subnetwork.CySubNetwork;
import org.cytoscape.view.layout.CyLayoutAlgorithm;
import org.cytoscape.view.model.CyNetworkView;
import org.cytoscape.work.Task;
import org.cytoscape.work.TaskIterator;
import org.cytoscape.work.TaskMonitor;
import de.hhu.ba.yoshikoWrapper.core.CyCore;
import de.hhu.ba.yoshikoWrapper.core.LocalizationManager;
import de.hhu.ba.yoshikoWrapper.cytoUtil.StyleManager;
public class YoshikoSolution {
/**
* The original Graph from which the solution was generated.
* NOTE: This can be destroyed or modified during runtime while the solution still exists and may become invalid
*/
private final CyNetwork originalGraph;
private final YoshikoResult result;
public ArrayList<YoshikoCluster> cluster;
private final long id;
public YoshikoSolution(CyNetwork originalGraph, long id) {
public YoshikoSolution(YoshikoResult yoshikoResult, long id) {
cluster = new ArrayList<YoshikoCluster>();
this.originalGraph = originalGraph;
this.result = yoshikoResult;
this.id = id;
}
//_____________GETTER / SETTER ________________//
public ArrayList<YoshikoCluster> getCluster() {
public ArrayList<YoshikoCluster> getClusters() {
return cluster;
}
public CyNetwork getOriginalGraph() {
return originalGraph;
}
/**
* @return the id
*/
......@@ -75,4 +52,8 @@ public class YoshikoSolution {
return id;
}
public CyNetwork getOriginalGraph() {
return result.getOriginalGraph();
}
}
......@@ -25,13 +25,10 @@ import static javax.swing.GroupLayout.DEFAULT_SIZE;
import static javax.swing.GroupLayout.PREFERRED_SIZE;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
......@@ -49,28 +46,34 @@ import de.hhu.ba.yoshikoWrapper.swing.SwingUtil;
@SuppressWarnings("serial")
public class ClusterView extends JPanel {
//MACRO / STATIC
private final static int CLUSTER_ICON_SIZE = 128;
private static final Border regularBorder = BorderFactory.createLineBorder(Color.GRAY,3);
private static final Border highlightBorder = BorderFactory.createLineBorder(GraphicsLoader.yoshikoGreen,3);
private static final Border selectedBorder = BorderFactory.createLineBorder(Color.BLUE,3);
//SWING COMPONENTS
private final JLabel title;
private final JLabel clusterSize;
private final JLabel icon;
private final BasicCollapsiblePanel nodeList;
private final Border regularBorder = BorderFactory.createLineBorder(Color.GRAY,3);
private final Border highlightBorder = BorderFactory.createLineBorder(GraphicsLoader.yoshikoGreen,3);
private final Border selectedBorder = BorderFactory.createLineBorder(Color.BLUE,3);
//INTERNAL
private boolean isSelected;
//SYMBOLIC LINKS
/**Simple array list containing references to the nodes that are represented by this cluster view
*
*/
private YoshikoCluster cluster;
public ClusterView(YoshikoCluster c) throws Exception {
this.cluster = c;
this.isSelected = false;
//Swing init
title = new JLabel(LocalizationManager.get("cluster")+" "+(c.getID()+1));
......@@ -108,7 +111,7 @@ public class ClusterView extends JPanel {
.addComponent(title,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
.addComponent(clusterSize,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE)
)
.addGap(6)
.addGap(12)
.addComponent(icon)
)
.addComponent(nodeList)
......@@ -119,7 +122,7 @@ public class ClusterView extends JPanel {
.addComponent(title)
.addComponent(clusterSize)
)
.addGap(6)
.addGap(12)
.addComponent(icon)
)
.addComponent(nodeList)
......@@ -132,24 +135,25 @@ public class ClusterView extends JPanel {
private MouseListener mouseListener = new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
cluster.highlightInOriginalGraph();
public void mouseClicked(MouseEvent e) {
isSelected = !isSelected;
setBorder(isSelected ? selectedBorder : regularBorder);
}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {
setBorder(highlightBorder);
cluster.highlightInOriginalGraph();
setBorder(isSelected ? selectedBorder : highlightBorder);
}
@Override
public void mouseExited(MouseEvent e) {
setBorder(regularBorder);
setBorder(isSelected ? selectedBorder : regularBorder);
}
......
package de.hhu.ba.yoshikoWrapper.swing.components;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Scrollable;
import org.slf4j.Logger;
import de.hhu.ba.yoshikoWrapper.logging.YoshikoLogger;
@SuppressWarnings("serial")
public class ClusterViewList extends JPanel implements Scrollable {
private static final Logger logger = YoshikoLogger.getInstance().getLogger();
@Override
public Dimension getPreferredScrollableViewportSize() {
return this.getPreferredSize();
......@@ -34,4 +42,24 @@ public class ClusterViewList extends JPanel implements Scrollable {
return false;
}
@Override
public ClusterView add(Component c) throws NullPointerException{
//Simple type check
if (c instanceof ClusterView) {
return (ClusterView) super.add(c);
}
logger.error("Attempted to add a component to ClusterViewList that is not a ClusterView");
return null;
}
public ArrayList<ClusterView> getClusterViews() {
ArrayList<ClusterView> ret = new ArrayList<ClusterView>();
for (Component c : this.getComponents()) {
if (c instanceof ClusterView) {
ret.add((ClusterView)c);
}
}
return ret;
}
}
......@@ -25,9 +25,10 @@ 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.Properties;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
......@@ -41,6 +42,18 @@ import javax.swing.JTabbedPane;
import org.cytoscape.application.swing.CytoPanelComponent;
import org.cytoscape.application.swing.CytoPanelName;
import org.cytoscape.event.AbstractCyEvent;
import org.cytoscape.model.CyNetwork;
import org.cytoscape.model.events.AboutToRemoveEdgesEvent;
import org.cytoscape.model.events.AboutToRemoveEdgesListener;
import org.cytoscape.model.events.AboutToRemoveNodesEvent;
import org.cytoscape.model.events.AboutToRemoveNodesListener;
import org.cytoscape.model.events.AddedEdgesEvent;
import org.cytoscape.model.events.AddedEdgesListener;
import org.cytoscape.model.events.AddedNodesEvent;
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 de.hhu.ba.yoshikoWrapper.core.CyCore;
......@@ -54,13 +67,27 @@ import de.hhu.ba.yoshikoWrapper.swing.SwingUtil;
* Conforms to CY 3.5 by being a CytoPanelComponent which is the norm for "result" panels
*/
@SuppressWarnings("serial")//Will never be serialized
public class ResultPanel extends JPanel implements CytoPanelComponent{
public class ResultPanel extends JPanel implements CytoPanelComponent,
//Implements listeners to invalidate results when the graph the result was generated for changes
AboutToRemoveEdgesListener,
AboutToRemoveNodesListener,
AddedEdgesListener,
AddedNodesListener,
NetworkAboutToBeDestroyedListener
{
//MACRO
private static final int HACKFIX_FIXED_WIDTH = 128+256;
private final JTabbedPane tabbedPane;
private final JTabbedPane solutionTabs;
private final JButton destroyButton;
private BasicCollapsiblePanel marker;
private final JLabel invalidLabel;
private ArrayList<SolutionTab> solutionTabs;
private final YoshikoResult result;
public ResultPanel(YoshikoResult result) throws Exception {
......@@ -68,17 +95,21 @@ public class ResultPanel extends JPanel implements CytoPanelComponent{
this.result = result;
//Init subcomponents
solutionTabs = new JTabbedPane();
for (YoshikoSolution s : result.solutions) {
addSolutionTab(s);
}
if (result.flags.getIlpGenerated()) {
System.out.println("Setting up ILP Info Marker");
invalidLabel = new JLabel();
tabbedPane = new JTabbedPane();
for (YoshikoSolution s : result.getSolutions()) {
SolutionTab tab = new SolutionTab(s);
tabbedPane.add(
LocalizationManager.get("solution")+" "+(s.getId()+1),
tab
); }
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.flags.getOptimal()) {
if(result.getFlags().getOptimal()) {
JLabel optimalLabel;
optimalLabel = new JLabel(LocalizationManager.get("optimal"));
optimalLabel.setForeground(GraphicsLoader.yoshikoGreen);
......@@ -89,12 +120,12 @@ public class ResultPanel extends JPanel implements CytoPanelComponent{
optimalLabel = new JLabel(LocalizationManager.get("notOptimal"));
optimalLabel.setForeground(Color.RED);
marker.add(optimalLabel);
marker.add(new JLabel(result.flags.getSolvedInstances()+"/"+result.flags.getReducedInstances()+" "+LocalizationManager.get("redSolved")));
marker.add(new JLabel(LocalizationManager.get("lastInstanceGap")+" "+(int)(100*result.flags.getLastGap())+"%"));
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.flags.getTotalCost());
JLabel costLabel = new JLabel(LocalizationManager.get("cost")+" "+result.getFlags().getTotalCost());
marker.add(costLabel);
if (result.flags.getTimedOut()) {
if (result.getFlags().getTimedOut()) {
marker.add(new JLabel(LocalizationManager.get("timeoutMarker")));
}
marker.setCollapsed(false);
......@@ -111,7 +142,7 @@ public class ResultPanel extends JPanel implements CytoPanelComponent{
});
SwingUtil.addAll(this,solutionTabs,destroyButton);
SwingUtil.addAll(this,invalidLabel,tabbedPane,destroyButton);
//Layout
GroupLayout layout = new GroupLayout(this);
......@@ -122,16 +153,18 @@ public class ResultPanel extends JPanel implements CytoPanelComponent{
layout.setHorizontalGroup(horizontalGroup);
layout.setVerticalGroup(verticalGroup);
if (result.flags.getIlpGenerated()) {
if (result.getFlags().getIlpGenerated()) {
horizontalGroup.addComponent(marker,DEFAULT_SIZE,DEFAULT_SIZE,DEFAULT_SIZE);
verticalGroup.addComponent(marker,DEFAULT_SIZE,DEFAULT_SIZE,PREFERRED_SIZE);
}
horizontalGroup
.addComponent(solutionTabs,DEFAULT_SIZE, DEFAULT_SIZE,Short.MAX_VALUE)
.addComponent(invalidLabel,HACKFIX_FIXED_WIDTH, 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(solutionTabs,DEFAULT_SIZE, DEFAULT_SIZE,PREFERRED_SIZE)
.addComponent(invalidLabel,DEFAULT_SIZE, DEFAULT_SIZE,PREFERRED_SIZE)
.addComponent(tabbedPane,DEFAULT_SIZE, DEFAULT_SIZE,PREFERRED_SIZE)
.addComponent(destroyButton,DEFAULT_SIZE, DEFAULT_SIZE,PREFERRED_SIZE);
layout.setAutoCreateGaps(true);
......@@ -139,7 +172,17 @@ public class ResultPanel extends JPanel implements CytoPanelComponent{
this.setLayout(layout);
this.setPreferredSize(new Dimension(this.getPreferredSize().width*2,this.getPreferredSize().height));
registerAllListeners();
}
private void registerAllListeners() {
CyCore.registrar.registerService(this, AboutToRemoveEdgesListener.class, new Properties());
CyCore.registrar.registerService(this, AboutToRemoveNodesListener.class, new Properties());
CyCore.registrar.registerService(this, AddedEdgesListener.class, new Properties());