source: src/main/java/weka/gui/graphvisualizer/HierarchicalBCEngine.java @ 16

Last change on this file since 16 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 74.8 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    HierarchicalBCEngine.java
19 *    Copyright (C) 2003 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.graphvisualizer;
24
25import weka.core.FastVector;
26import weka.gui.graphvisualizer.GraphNode;
27import weka.gui.graphvisualizer.GraphEdge;
28
29import javax.swing.JPanel;
30import javax.swing.JRadioButton;
31import javax.swing.JCheckBox;
32import javax.swing.ButtonGroup;
33import javax.swing.BorderFactory;
34import javax.swing.JProgressBar;
35
36import java.awt.event.ActionListener;
37import java.awt.event.ActionEvent;
38import java.awt.GridBagLayout;
39import java.awt.GridBagConstraints;
40
41/**
42 * This class lays out the vertices of a graph in a
43 * hierarchy of vertical levels, with a number of nodes
44 * in each level. The number of levels is the depth of
45 * the deepest child reachable from some parent at level
46 * 0. It implements a layout technique as described by
47 * K. Sugiyama, S. Tagawa, and M. Toda. in "Methods for
48 * visual understanding of hierarchical systems", IEEE
49 * Transactions on Systems, Man and Cybernetics,
50 * SMC-11(2):109-125, Feb. 1981.
51 * <p>There have been a few modifications made, however.
52 * The crossings function is changed as it was non-linear
53 * in time complexity. Furthermore, we don't have any
54 * interconnection matrices for each level, instead we
55 * just have one big interconnection matrix for the
56 * whole graph and a int[][] array which stores the
57 * vertices present in each level.
58 *
59 * @author Ashraf M. Kibriya (amk14@cs.waikato.ac.nz)
60 * @version $Revision: 1.6 $ - 24 Apr 2003 - Initial version (Ashraf M. Kibriya)
61 *
62 */
63public class HierarchicalBCEngine implements GraphConstants, LayoutEngine {
64 
65  /** FastVector containing nodes and edges */
66  protected FastVector m_nodes, m_edges;
67  /**  FastVector containing listeners for
68    * layoutCompleteEvent generated by this
69    * LayoutEngine  */
70  protected FastVector layoutCompleteListeners;
71  /**   Interconnection matrix for the graph  */
72  protected int graphMatrix[][];
73  /** Array containing the indices of nodes in each level.
74    * The nodeLevels.length is equal to the number of levels  */
75  protected int nodeLevels[][];
76  /** The nodeWidth and nodeHeight */
77  protected int m_nodeWidth, m_nodeHeight;
78 
79  /* The following radio buttons control the
80     way the layout is performed. If any
81     of the following is changed then we
82     need to perform a complete relayout
83   */
84  protected JRadioButton m_jRbNaiveLayout;
85  protected JRadioButton m_jRbPriorityLayout;
86  protected JRadioButton m_jRbTopdown;
87  protected JRadioButton m_jRbBottomup;
88 
89  /** controls edge concentration by concentrating multilple singular dummy
90   * child nodes into one plural dummy child node
91   */
92  protected JCheckBox m_jCbEdgeConcentration;
93 
94  /** The panel containing extra options,
95   * specific to this LayoutEngine, for
96   * greater control over layout of the graph */
97  protected JPanel m_controlsPanel;
98 
99  /** The progress bar to show the progress
100   * of the layout process */
101  protected JProgressBar m_progress;
102 
103  /** This tells the the LayoutGraph method if
104   * a completeReLayout should be performed
105   * when it is called. */
106  protected boolean m_completeReLayout=false;
107 
108  /** This contains the original size of the nodes vector
109   * when it was passed in through the constructor, before
110   * adding all the dummy vertices */
111  private int origNodesSize;
112 
113  /** Constructor - takes in FastVectors of nodes and edges, and the initial
114   *  width and height of a node
115   */
116  public HierarchicalBCEngine(FastVector nodes, FastVector edges, int nodeWidth, 
117                              int nodeHeight) {
118    m_nodes = nodes; m_edges = edges; m_nodeWidth = nodeWidth; 
119    m_nodeHeight = nodeHeight;
120    makeGUIPanel(false);
121  }
122 
123  /** Constructor - takes in FastVectors of nodes and edges, the initial width
124   * and height of a node, and a boolean value to indicate if the edges
125   * should be concentrated.
126   * @param nodes - FastVector containing all the nodes
127   * @param edges - FastVector containing all the edges
128   * @param nodeWidth - A node's allowed width
129   * @param nodeHeight - A node's allowed height
130   * @param edgeConcentration - True: if want to concentrate edges,
131   * False: otherwise
132   */
133  public HierarchicalBCEngine(FastVector nodes, FastVector edges,
134  int nodeWidth, int nodeHeight, boolean edgeConcentration) {
135    m_nodes = nodes; m_edges = edges; m_nodeWidth = nodeWidth; 
136    m_nodeHeight = nodeHeight;
137    makeGUIPanel(edgeConcentration);
138  }
139 
140  /** SimpleConstructor
141   * If we want to instantiate the class first, and if information for
142   * nodes and edges is not available. However, we would have to manually
143   * provide all the information later on by calling setNodesEdges and
144   * setNodeSize methods
145   */
146  public HierarchicalBCEngine() {   }
147 
148  /**
149   * This methods makes the gui extra controls panel "m_controlsPanel"
150   */
151  protected void makeGUIPanel(boolean edgeConc) {
152    m_jRbNaiveLayout = new JRadioButton("Naive Layout");
153    m_jRbPriorityLayout = new JRadioButton("Priority Layout");
154    ButtonGroup bg = new ButtonGroup();
155    bg.add(m_jRbNaiveLayout);
156    bg.add(m_jRbPriorityLayout);
157    m_jRbPriorityLayout.setSelected(true);
158   
159    ActionListener a = new ActionListener() {
160      public void actionPerformed(ActionEvent ae) {
161        m_completeReLayout=true;
162      }
163    };
164   
165    m_jRbTopdown = new JRadioButton("Top Down");
166    m_jRbBottomup = new JRadioButton("Bottom Up");
167    m_jRbTopdown.addActionListener(a);
168    m_jRbBottomup.addActionListener(a);
169    bg = new ButtonGroup();
170    bg.add(m_jRbTopdown);
171    bg.add(m_jRbBottomup);
172    m_jRbBottomup.setSelected(true);
173   
174    m_jCbEdgeConcentration = new JCheckBox("With Edge Concentration", edgeConc);
175    m_jCbEdgeConcentration.setSelected(edgeConc);
176    m_jCbEdgeConcentration.addActionListener(a);
177   
178    JPanel jp1 = new JPanel( new GridBagLayout() );
179    GridBagConstraints gbc = new GridBagConstraints();
180    gbc.gridwidth = gbc.REMAINDER;
181    gbc.anchor = gbc.NORTHWEST;
182    gbc.weightx = 1;
183    gbc.fill = gbc.HORIZONTAL;
184    jp1.add(m_jRbNaiveLayout, gbc);
185    jp1.add(m_jRbPriorityLayout, gbc);
186    jp1.setBorder( BorderFactory.createTitledBorder("Layout Type") );
187   
188    JPanel jp2 = new JPanel( new GridBagLayout() );
189    jp2.add(m_jRbTopdown, gbc);
190    jp2.add(m_jRbBottomup, gbc);
191    jp2.setBorder( BorderFactory.createTitledBorder("Layout Method") );
192   
193   
194    m_progress = new JProgressBar(0, 11);
195    m_progress.setBorderPainted(false);
196    m_progress.setStringPainted(true);
197    m_progress.setString("");
198   
199    m_progress.setValue(0);
200   
201    m_controlsPanel = new JPanel( new GridBagLayout() );
202    m_controlsPanel.add(jp1, gbc);
203    m_controlsPanel.add(jp2, gbc);
204    m_controlsPanel.add(m_jCbEdgeConcentration, gbc);
205  }
206 
207    /** give access to set of graph nodes */
208    public FastVector getNodes() {
209        return m_nodes;
210    }
211 
212  /** This method returns a handle to the extra
213   * controls panel, so that the visualizing
214   * class can add it to some of it's own
215   * gui panel.
216   */
217  public JPanel getControlPanel() {
218    return m_controlsPanel;
219  }
220 
221  /** Returns a handle to the progressBar
222   * of this LayoutEngine.
223   */
224  public JProgressBar getProgressBar() {
225    return m_progress;
226  }
227 
228  /** Sets the nodes and edges for this LayoutEngine.
229   * Must be used if the class created by simple
230   * HierarchicalBCEngine() constructor.
231   * @param nodes - FastVector containing all the nodes
232   * @param edges - FastVector containing all the edges
233   */
234  public void setNodesEdges(FastVector nodes, FastVector edges) {
235    m_nodes = nodes; m_edges = edges;
236  }
237 
238  /**
239   * Sets the size of a node. This method must be
240   *    used if the class created by simple
241   *    HierarchicalBCEngine() constructor.
242   *    @param nodeWidth - A node's allowed width
243   *    @param nodeHeight - A node's allowed height
244   */
245  public void setNodeSize(int nodeWidth, int nodeHeight) {
246    m_nodeWidth = nodeWidth;
247    m_nodeHeight = nodeHeight;
248  }
249 
250  /**
251   * Method to add a LayoutCompleteEventListener
252   * @param l - Listener to receive the LayoutCompleteEvent by this
253   *            class.
254   */
255  public void addLayoutCompleteEventListener(LayoutCompleteEventListener l) {
256    if(layoutCompleteListeners==null)
257      layoutCompleteListeners = new FastVector();
258    layoutCompleteListeners.addElement(l);
259  }
260 
261  /**
262   * Method to remove a LayoutCompleteEventListener.
263   * @param e - The LayoutCompleteEventListener to remove.
264   */
265  public void removeLayoutCompleteEventListener(LayoutCompleteEventListener e){
266    if(layoutCompleteListeners!=null) {
267      LayoutCompleteEventListener l;
268     
269      for(int i=0; i<layoutCompleteListeners.size(); i++) {
270        l = (LayoutCompleteEventListener) layoutCompleteListeners.elementAt(i);
271        if(l==e) {
272          layoutCompleteListeners.removeElementAt(i);
273          return;
274        }
275      }
276      System.err.println("layoutCompleteListener to be remove not present");
277    }
278    else
279      System.err.println("layoutCompleteListener to be remove not present");
280  }
281 
282  /**
283   * Fires a LayoutCompleteEvent.
284   * @param e - The LayoutCompleteEvent to fire
285   */
286  public void fireLayoutCompleteEvent(LayoutCompleteEvent e) {
287    if(layoutCompleteListeners!=null && layoutCompleteListeners.size()!=0) {
288      LayoutCompleteEventListener l;
289     
290      for(int i=0; i<layoutCompleteListeners.size(); i++) {
291        l = (LayoutCompleteEventListener) layoutCompleteListeners.elementAt(i);
292        l.layoutCompleted(e);
293      }
294    }
295  }
296 
297 
298  /**
299   * This method does a complete layout of the graph which includes
300   * removing cycles, assigning levels to nodes, reducing edge crossings
301   * and laying out the vertices horizontally for better visibility.
302   * The removing of cycles and assignment of levels is only performed
303   * if hasn't been performed earlier or if some layout option has been
304   * changed and it is necessary to do so. It is necessary to do so,
305   * if the user selects/deselects edge concentration or topdown/bottomup
306   * options.
307   * <p> The layout is performed in a separate thread and the progress
308   * bar of the class is updated for each of the steps as the process
309   * continues.
310   */
311  public void layoutGraph() {
312  //cannot perform a layout if no description of nodes and/or edges is provided
313    if(m_nodes==null || m_edges==null)
314      return; 
315   
316    Thread th = new Thread() {
317      public void run() {
318        m_progress.setBorderPainted(true);
319        if(nodeLevels==null) {
320          makeProperHierarchy();
321        }
322        else if(m_completeReLayout==true) {
323          clearTemps_and_EdgesFromNodes(); makeProperHierarchy(); 
324          m_completeReLayout=false;
325        }
326       
327        //minimizing crossings
328        if(m_jRbTopdown.isSelected()) {
329          int crossbefore=crossings(nodeLevels), crossafter=0, i=0;
330          do {
331            m_progress.setValue(i+4);
332            m_progress.setString("Minimizing Crossings: Pass"+(i+1));
333            if(i!=0)
334              crossbefore = crossafter;
335            nodeLevels = minimizeCrossings(false, nodeLevels);
336            crossafter = crossings(nodeLevels);
337            i++;
338          }
339          while(crossafter<crossbefore && i<6);
340        }
341        else {
342          int crossbefore=crossings(nodeLevels), crossafter=0, i=0;
343          do {
344            m_progress.setValue(i+4);
345            m_progress.setString("Minimizing Crossings: Pass"+(i+1));
346            if(i!=0)
347              crossbefore = crossafter;
348            nodeLevels = minimizeCrossings(true, nodeLevels);
349            crossafter = crossings(nodeLevels);
350            i++;
351          }
352          while(crossafter<crossbefore && i<6);
353        }
354        //System.out.println("\nCrossings at the end "+
355        //                   crossings(nodeLevels)+
356        //                   "\n---------------------------------");
357       
358        m_progress.setValue(10);
359        m_progress.setString("Laying out vertices");
360        //Laying out graph
361        if(m_jRbNaiveLayout.isSelected())
362          naiveLayout();
363        else
364          priorityLayout1();
365        m_progress.setValue(11);
366        m_progress.setString("Layout Complete");
367        m_progress.repaint();
368       
369        fireLayoutCompleteEvent( new LayoutCompleteEvent(this) );
370        m_progress.setValue(0);
371        m_progress.setString("");
372        m_progress.setBorderPainted(false);
373      }
374    };
375    th.start();
376  }
377 
378  /**
379   * This method removes the temporary nodes that were
380   * added to fill in the gaps, and removes all edges
381   * from all nodes in their edges[][] array
382   */
383  protected void clearTemps_and_EdgesFromNodes() {
384    /*
385    System.out.println("Before.............");
386    for(int i=0; i<m_nodes.size(); i++) {
387      GraphNode n = (GraphNode)m_nodes.elementAt(i);
388      System.out.println("N: "+n.ID+","+i);
389    }
390    System.out.println("origNodesSize: "+origNodesSize);
391    */
392   
393    int curSize = m_nodes.size();
394    for(int i=origNodesSize; i<curSize; i++)
395      m_nodes.removeElementAt(origNodesSize);
396    for(int j=0; j<m_nodes.size(); j++)
397      ((GraphNode)m_nodes.elementAt(j)).edges = null;
398   
399    nodeLevels=null;
400   
401    /*
402    System.out.println("After..............");
403    for(int i=0; i<m_nodes.size(); i++) {
404      GraphNode n = (GraphNode)m_nodes.elementAt(i);
405      System.out.println("N: "+n.ID+","+i);
406    }
407    */
408  }
409 
410  /**
411   * This method makes the "graphMatrix" interconnection
412   * matrix for the graph given by m_nodes and m_edges
413   * vectors. The matix is used by other methods.
414   */
415  protected void processGraph() {
416    origNodesSize = m_nodes.size();
417    graphMatrix = new int[m_nodes.size()][m_nodes.size()];
418    /*
419    System.out.println("The "+m_nodes.size()+" nodes are: ");
420    for(int i=0; i<m_nodes.size(); i++)
421      System.out.println((String)m_nodes.elementAt(i)+" ");
422    System.out.println("\nThe "+m_edges.size()+" edges are: ");
423    for(int i=0; i<m_edges.size(); i++)
424      System.out.println((GraphEdge)m_edges.elementAt(i));
425    */
426    for(int i=0; i<m_edges.size(); i++)
427      graphMatrix[((GraphEdge)m_edges.elementAt(i)).src]
428                 [((GraphEdge)m_edges.elementAt(i)).dest] = 
429                                         ((GraphEdge)m_edges.elementAt(i)).type;
430    /*
431    System.out.print("\t");
432    for(int i=0; i<graphMatrix.length; i++)
433      System.out.print(((GraphNode)m_nodes.elementAt(i)).ID+" ");
434    System.out.println("");
435    for(int i=0; i<graphMatrix.length; i++) {
436      GraphNode n = (GraphNode)m_nodes.elementAt(i);
437      System.out.print(n.ID+"\t");
438      for(int j=0; j<graphMatrix[i].length; j++)
439        System.out.print(graphMatrix[i][j]+" ");
440      System.out.println("");
441    }
442    */
443  }
444 
445  /*
446   * This method makes a proper hierarchy of the graph
447   * by first removing cycles, then assigning levels
448   * to the nodes and then removing gaps by adding
449   * dummy vertices.
450   */
451  protected void makeProperHierarchy() {
452    processGraph();
453   
454    m_progress.setValue(1);
455    m_progress.setString("Removing Cycles");
456    //****removing cycles
457    removeCycles();
458   
459    m_progress.setValue(2);
460    m_progress.setString("Assigning levels to nodes");
461    //****Assigning vertical level to each node
462    int nodesLevel[] = new int[m_nodes.size()];
463    int depth=0;
464    for(int i=0; i<graphMatrix.length; i++) {
465      assignLevels(nodesLevel, depth, i, 0);
466    }
467   
468    for(int i=0; i<nodesLevel.length; i++) {
469      if(nodesLevel[i]==0) {
470        int min=65536;
471        for(int j=0; j<graphMatrix[i].length; j++) {
472          if(graphMatrix[i][j]==DIRECTED)
473            if(min>nodesLevel[j])
474              min = nodesLevel[j];
475        }
476        //if the shallowest child of a parent has a depth greater than 1
477        // and it is not a lone parent with no children
478        if(min!=65536 && min>1) 
479          nodesLevel[i]=min-1;       
480      }
481    }
482   
483    //System.out.println("");
484    int maxLevel=0;
485    for(int i=0; i<nodesLevel.length; i++) {
486      if(nodesLevel[i]>maxLevel)
487        maxLevel = nodesLevel[i];
488      //System.out.println( ((GraphNode)m_nodes.elementAt(i)).ID+" "+i+">"+
489      //                    nodesLevel[i]);
490    }
491    int levelCounts[] = new int[maxLevel+1];
492   
493    for(int i=0; i<nodesLevel.length; i++) {
494      levelCounts[nodesLevel[i]]++;
495    }
496    //System.out.println("------------------------------------------");
497    //****Assigning nodes to each level
498    int levelsCounter[] = new int[maxLevel+1];
499    nodeLevels = new int[maxLevel+1][];
500    for(byte i=0; i<nodesLevel.length; i++) {
501      if(nodeLevels[nodesLevel[i]]==null)
502        nodeLevels[nodesLevel[i]] = new int[ levelCounts[nodesLevel[i]] ];
503      //nodeLevels[nodesLevel[i]].addElement(new Integer(i));
504      //System.out.println(((GraphNode)m_nodes.elementAt(i)).ID+" "+
505      //                   nodesLevel[i]+">"+levelCounts[nodesLevel[i]]);
506      nodeLevels[nodesLevel[i]][levelsCounter[nodesLevel[i]]++] = i;
507    }
508   
509    m_progress.setValue(3);
510    m_progress.setString("Removing gaps by adding dummy vertices");
511    //*Making a proper Hierarchy by putting in dummy vertices to close all gaps
512    if(m_jCbEdgeConcentration.isSelected())
513      removeGapsWithEdgeConcentration(nodesLevel);
514    else
515      removeGaps(nodesLevel);
516   
517    //After assigning levels and adding dummy vertices
518    //System.out.print("\n\t");
519    //for(int i=0; i<graphMatrix.length; i++)
520    //    System.out.print(((GraphNode)m_nodes.elementAt(i)).ID+" ");
521    //System.out.println("");
522    //for(int i=0; i<graphMatrix.length; i++) {
523    //    System.out.print(((GraphNode)m_nodes.elementAt(i)).ID+"\t");
524    //    for(int j=0; j<graphMatrix[i].length; j++)
525    //  System.out.print(graphMatrix[i][j]+" ");
526    //    System.out.println("");
527    //}
528   
529    //****Updating edges[][] array of nodes from
530    //****the interconnection matrix, which will be used
531    //****by the Visualizer class to draw edges
532    for(int i=0; i<graphMatrix.length; i++) {
533      GraphNode n = (GraphNode)m_nodes.elementAt(i);
534      int sum=0;
535      for(int j=0; j<graphMatrix[i].length; j++)
536        if(graphMatrix[i][j]!=0)
537          sum++;
538     
539      n.edges = new int[sum][2];
540      for(int j=0, k=0; j<graphMatrix[i].length; j++)
541        if(graphMatrix[i][j]!=0) {
542          n.edges[k][0] = j;
543          n.edges[k][1] = graphMatrix[i][j]; k++;
544        }
545      //n.edges = graphMatrix[i];
546    }
547   
548    //Interconnection matrices at each level, 1 to n-1
549    //printMatrices(nodeLevels);
550  }
551 
552 
553  /**
554   * This method removes gaps from the graph. It doesn't perform
555   * any concentration. It takes as an argument of int[]
556   * of length m_nodes.size() containing the level of each
557   * node.
558   */
559  private void removeGaps(int nodesLevel[]) {
560    int temp = m_nodes.size();
561    int temp2=graphMatrix[0].length, tempCnt=1;
562   
563    for(int n=0; n<temp; n++) {
564      for(int i=0; i<temp2; i++) {
565        int len = graphMatrix.length;
566        if(graphMatrix[n][i]>0)
567          if(nodesLevel[i]>nodesLevel[n]+1) {
568            int tempMatrix[][] =
569            new int[graphMatrix.length+(nodesLevel[i]-nodesLevel[n]-1)]
570                   [graphMatrix.length+(nodesLevel[i]-nodesLevel[n]-1)];
571            int level = nodesLevel[n]+1;
572            copyMatrix(graphMatrix, tempMatrix);
573           
574            String s1 = new String("S"+tempCnt++);
575            m_nodes.addElement(new GraphNode(s1, s1, SINGULAR_DUMMY)); //true));
576            int temp3 [] = new int[nodeLevels[level].length+1];
577            //for(int j=0; j<nodeLevels[level].length; j++)
578            //    temp3[j] = nodeLevels[level][j];
579            System.arraycopy(nodeLevels[level], 0, temp3, 
580                             0, nodeLevels[level].length);
581            temp3[temp3.length-1] = m_nodes.size()-1;
582            nodeLevels[level] = temp3; level++;
583            //nodeLevels[level++].addElement(new Integer(m_nodes.size()-1));
584            //System.out.println("len:"+len+","+nodesLevel[i]+","+
585            //                   nodesLevel[n]);
586           
587            int k;
588            for(k=len; k<len+nodesLevel[i]-nodesLevel[n]-1-1; k++) {
589              String s2 =  new String("S"+tempCnt);
590              m_nodes.addElement( new GraphNode(s2, s2, SINGULAR_DUMMY) ); //true) );
591              temp3 = new int[nodeLevels[level].length+1];
592              //for(int j=0; j<nodeLevels[level].length; j++)
593              //        temp3[j] = nodeLevels[level][j];
594              System.arraycopy(nodeLevels[level], 0, temp3, 
595                               0, nodeLevels[level].length);
596              temp3[temp3.length-1] = m_nodes.size()-1;
597              nodeLevels[level++] = temp3;
598              //nodeLevels[level++].addElement(new Integer(m_nodes.size()-1));
599              tempMatrix[k][k+1]=tempMatrix[n][i]; tempCnt++;
600              if(k>len)
601                tempMatrix[k][k-1]=-1*tempMatrix[n][i];
602            }
603           
604            //temp[lastTempNodeCreated][targetNode]=temp[origNode][targetNode]
605            tempMatrix[k][i]=tempMatrix[n][i];
606            //System.out.println("k "+((GraphNode)m_nodes.elementAt(k)).ID+
607            //             " i "+((GraphNode)m_nodes.elementAt(i)).ID+
608            //             " n "+((GraphNode)m_nodes.elementAt(n)).ID+
609            //             " len "+((GraphNode)m_nodes.elementAt(len)).ID );
610            //temp[origNode][firstTempNodecreated] = temp[origNode][targetNode]
611            tempMatrix[n][len] = tempMatrix[n][i]; 
612            //temp[firstTempNodeCreated][origNode]  for reverse tracing
613            tempMatrix[len][n] = -1*tempMatrix[n][i];
614             //temp[targetNode][lastTempNodecreated]  for reverse tracing
615            tempMatrix[i][k]   = -1*tempMatrix[n][i]; 
616           
617            //temp[lastTempNodeCreated][secondlastNode] for reverse tracing
618            //but only do this if more than 1 temp nodes are created
619            if(k>len)                                 
620              tempMatrix[k][k-1] = -1*tempMatrix[n][i];
621           
622            //temp[origNode][targetNode] = 0 unlinking as they have been
623            // linked by a chain of temporary nodes now.
624            tempMatrix[n][i]   = 0;                   
625            tempMatrix[i][n]   = 0;                   
626           
627            graphMatrix = tempMatrix;
628          }
629          else {
630            //****Even if there is no gap just add a reference for the
631            //****parent to the child for reverse tracing, useful if the
632            //****there is a reversed edge from parent to child and therefore
633            //****visualizer would know to highlight this edge  when
634            //****highlighting the child.
635            graphMatrix[i][n]=-1*graphMatrix[n][i];
636          }
637      }
638    }
639    //Interconnection matrices at each level, 1 to n-1 after minimizing edges
640    //printMatrices(nodeLevels);
641  }
642 
643 
644  /**
645   * This method removes gaps from the graph. It tries to minimise the number
646   * of edges by concentrating multiple dummy nodes from the same parent and
647   * on the same vertical level into one. It takes as an argument of int[]
648   * of length m_nodes.size() containing the level of each
649   * node.
650   */
651  private void removeGapsWithEdgeConcentration(int nodesLevel[]) {
652   
653    final int  temp = m_nodes.size(), temp2=graphMatrix[0].length;
654    int tempCnt=1;
655   
656    for(int n=0; n<temp; n++) {
657      for(int i=0; i<temp2; i++) {
658        if(graphMatrix[n][i]>0)
659          if(nodesLevel[i]>nodesLevel[n]+1) {
660            //System.out.println("Processing node "+
661            //                   ((GraphNode)m_nodes.elementAt(n)).ID+
662            //                   " for "+((GraphNode)m_nodes.elementAt(i)).ID);
663            int tempLevel=nodesLevel[n];
664            boolean tempNodePresent=false;
665            int k=temp;
666            int tempnode = n;
667           
668            while(tempLevel < nodesLevel[i]-1 ) {
669              tempNodePresent=false;
670              for(; k<graphMatrix.length; k++) {
671                if(graphMatrix[tempnode][k]>0) {
672                  //System.out.println("tempnode will be true");
673                  tempNodePresent = true; break;
674                }
675              }
676              if(tempNodePresent) {
677                tempnode=k; k=k+1;
678                tempLevel++;
679              }
680              else {
681                if(tempnode!=n)
682                  tempnode=k-1;
683                //System.out.println("breaking from loop");
684                break;
685              }
686            }
687            if(((GraphNode)m_nodes.elementAt(tempnode)).nodeType==SINGULAR_DUMMY)
688              ((GraphNode)m_nodes.elementAt(tempnode)).nodeType=PLURAL_DUMMY;
689            if(tempNodePresent) {
690              //Link the last known temp node to target
691              graphMatrix[tempnode][i] = graphMatrix[n][i];
692              //System.out.println("modifying "+
693              //                   ((GraphNode)nodes.elementAt(tempnode)).ID+
694              //                   ", "+((GraphNode)nodes.elementAt(n)).ID);
695              /////matrix[lastknowntempnode][source]=-original_val
696              /////graphMatrix[tempnode][n] = -graphMatrix[n][i];
697              //System.out.println("modifying "+
698              //                   ((GraphNode)nodes.elementAt(i)).ID+
699              //                   ", "+
700              //                   ((GraphNode)nodes.elementAt(tempnode)).ID);
701             
702              //and matrix[target][lastknowntempnode]=-original_val
703              //for reverse tracing
704              graphMatrix[i][tempnode] = -graphMatrix[n][i];
705              //unlink source from the target
706              graphMatrix[n][i] = 0;
707              graphMatrix[i][n] = 0;
708              continue;
709             
710            }
711           
712            int len = graphMatrix.length;
713            int tempMatrix[][] =
714            new int[graphMatrix.length+(nodesLevel[i]-nodesLevel[tempnode]-1)]
715            [graphMatrix.length+(nodesLevel[i]-nodesLevel[tempnode]-1)];
716            int level = nodesLevel[tempnode]+1;
717            copyMatrix(graphMatrix, tempMatrix);
718           
719            String s1 = new String("S"+tempCnt++);
720            //System.out.println("Adding dummy "+s1);
721            m_nodes.addElement(new GraphNode(s1, s1, SINGULAR_DUMMY));
722           
723            int temp3 [] = new int[nodeLevels[level].length+1];
724            System.arraycopy(nodeLevels[level], 0, temp3, 
725                             0, nodeLevels[level].length);
726            temp3[temp3.length-1] = m_nodes.size()-1;
727            nodeLevels[level] = temp3;
728            temp3 = new int[m_nodes.size()+1];
729            System.arraycopy(nodesLevel, 0, temp3, 0, nodesLevel.length);
730            temp3[m_nodes.size()-1] = level;
731            nodesLevel = temp3;
732            level++;
733            //nodeLevels[level++].addElement(new Integer(m_nodes.size()-1));
734            //System.out.println("len:"+len+"("+
735            //                   ((GraphNode)m_nodes.elementAt(len)).ID+"),"+
736            //                   nodesLevel[i]+","+nodesLevel[tempnode]);
737           
738            int m;
739            for(m=len; m<len+nodesLevel[i]-nodesLevel[tempnode]-1-1; m++) {
740              String s2 =  new String("S"+tempCnt++);
741              //System.out.println("Adding dummy "+s2);
742              m_nodes.addElement( new GraphNode(s2, s2, SINGULAR_DUMMY) );
743              temp3 = new int[nodeLevels[level].length+1];
744              //for(int j=0; j<nodeLevels[level].length; j++)
745              //        temp3[j] = nodeLevels[level][j];
746              System.arraycopy(nodeLevels[level], 0, temp3, 
747                               0, nodeLevels[level].length);
748              temp3[temp3.length-1] = m_nodes.size()-1;
749              nodeLevels[level] = temp3;
750              temp3 = new int[m_nodes.size()+1];
751              System.arraycopy(nodesLevel, 0, temp3, 0, nodesLevel.length);
752              temp3[m_nodes.size()-1] = level;
753              nodesLevel = temp3;
754              level++;
755              //nodeLevels[level++].addElement(new Integer(m_nodes.size()-1));
756              //System.out.println("modifying "+
757              //                   ((GraphNode)nodes.elementAt(m)).ID+", "+
758              //                   ((GraphNode)nodes.elementAt(m+1)).ID);
759              tempMatrix[m][m+1]=tempMatrix[n][i]; //tempCnt++;
760              if(m>len) {
761                //System.out.println("modifying "+
762                //                   ((GraphNode)nodes.elementAt(m)).ID+
763                //                   ", "+((GraphNode)nodes.elementAt(m-1)).ID);
764                tempMatrix[m][m-1]=-1*tempMatrix[n][i];
765              }
766            }
767            //System.out.println("m "+((GraphNode)m_nodes.elementAt(m)).ID+
768            //     " i "+((GraphNode)m_nodes.elementAt(i)).ID+
769            //     " tempnode "+((GraphNode)m_nodes.elementAt(tempnode)).ID+
770            //     " len "+((GraphNode)m_nodes.elementAt(len)).ID );
771            //System.out.println("modifying "+
772            //                   ((GraphNode)nodes.elementAt(m)).ID+", "+
773            //                   ((GraphNode)nodes.elementAt(i)).ID);
774           
775            //temp[lastTempNodeCreated][targetNode]=temp[origNode][targetNode]
776            tempMatrix[m][i]=tempMatrix[n][i];
777            //System.out.println("modifying "+
778            //                   ((GraphNode)nodes.elementAt(tempnode)).ID+", "+
779            //                   ((GraphNode)nodes.elementAt(len)).ID);
780           
781            //temp[origNode][firstTempNodecreated] = temp[origNode][targetNode]
782            tempMatrix[tempnode][len] =  tempMatrix[n][i];
783            //System.out.println("modifying "+
784            //                   ((GraphNode)nodes.elementAt(len)).ID+", "+
785            //                   ((GraphNode)nodes.elementAt(tempnode)).ID);
786           
787            //temp[firstTempNodeCreated][origNode]  for reverse tracing
788            tempMatrix[len][tempnode] = -1*tempMatrix[n][i]; 
789            //System.out.println("modifying "+
790            //                   ((GraphNode)nodes.elementAt(i)).ID+", "+
791            //                   ((GraphNode)nodes.elementAt(m)).ID);
792           
793            //temp[targetNode][lastTempNodecreated]  for reverse tracing
794            tempMatrix[i][m] = -1*tempMatrix[n][i];
795            if(m>len) {
796              //System.out.println("modifying "+
797              //                   ((GraphNode)nodes.elementAt(m)).ID+
798              //                   ", "+((GraphNode)nodes.elementAt(m-1)).ID);
799
800              //temp[lastTempNodeCreated][secondlastNode] for reverse tracing
801              //but only do this if more than 1 temp nodes are created
802              tempMatrix[m][m-1] = -1*tempMatrix[n][i]; 
803            }
804
805            //temp[origNode][targetNode] = 0 unlinking as they have been
806            tempMatrix[n][i]   = 0;
807           
808            //linked by a chain of temporary nodes now.
809            tempMatrix[i][n]   = 0;
810           
811            graphMatrix = tempMatrix;
812          }
813          else {
814            //System.out.println("modifying "+
815            //                   ((GraphNode)nodes.elementAt(i)).ID+", "+
816            //                   ((GraphNode)nodes.elementAt(n)).ID);
817            //****Even if there is no gap just add a reference for the
818            //****parent to the child for reverse tracing, useful if the
819            //****there is a reversed edge from parent to child and therefore
820            //****visualizer would know to highlight this edge  when
821            //****highlighting the child.
822            graphMatrix[i][n]=-1*graphMatrix[n][i];
823          }
824      }
825    }
826   
827  }
828 
829 
830  /**
831   * Returns the index of an element in a level.
832   * Must never be called with the wrong element and
833   * the wrong level, will throw an exception otherwise.
834   * It takes as agrument the index of the element (in the m_nodes vector)
835   * and the level it is supposed to be in (as each level contains the indices
836   * of the nodes present in that level).
837   */
838  private int indexOfElementInLevel(int element, int level[]) throws Exception {
839    int idx;
840   
841    for(int i=0; i<level.length; i++)
842      if(level[i]==element)
843        return i;
844    throw new Exception("Error. Didn't find element "+
845                        ((GraphNode)m_nodes.elementAt(element)).ID+
846                        " in level. Inspect code for "+
847                        "weka.gui.graphvisualizer.HierarchicalBCEngine");
848  }
849 
850 
851 
852  /**
853   * Computes the number of edge crossings in the whole graph
854   * Takes as an argument levels of nodes. It is essentially the
855   * same algorithm provided in Universitat des Saarlandes
856   * technical report A03/94 by Georg Sander.
857   */
858  protected int crossings(final int levels[][]) {
859    int sum=0;
860   
861    for(int i=0; i<levels.length-1; i++) {
862      //System.out.println("*****************Processing level "+i+
863      //                   "*****************************");
864      MyList upper = new MyList(), lower = new MyList();
865      MyListNode lastOcrnce[] = new MyListNode[m_nodes.size()];
866      int edgeOcrnce[] = new int[m_nodes.size()];
867     
868      for(int j=0,uidx=0,lidx=0; j<(levels[i].length+levels[i+1].length); j++) {
869        if((j%2==0 && uidx<levels[i].length) || lidx>=levels[i+1].length) {
870          int k1=0, k2=0, k3=0;
871          GraphNode n = (GraphNode) m_nodes.elementAt(levels[i][uidx]);
872          //Deactivating and counting crossings for all edges ending in it
873          //coming from bottom left
874          if(lastOcrnce[levels[i][uidx]]!=null) {
875            MyListNode temp = new MyListNode(-1); temp.next = upper.first;
876            try {
877              do {
878                temp = temp.next;
879                if(levels[i][uidx]==temp.n) {
880                  k1 = k1+1;
881                  k3 = k3+k2;
882                  //System.out.println("Removing from upper: "+temp.n);
883                  upper.remove(temp);
884                }
885                else
886                  k2 = k2+1;
887              } while(temp!=lastOcrnce[levels[i][uidx]]);
888            }
889            catch(NullPointerException ex) {
890              System.out.println("levels[i][uidx]: "+levels[i][uidx]+
891              " which is: "+((GraphNode)m_nodes.elementAt(levels[i][uidx])).ID+
892              " temp: "+temp+
893              " upper.first: "+upper.first);
894            ex.printStackTrace();
895            System.exit(-1);}
896           
897            lastOcrnce[levels[i][uidx]]=null;
898            sum = sum + k1*lower.size() + k3;
899          }
900          //Activating all the edges going out towards the bottom
901          //and bottom right
902          for(int k=0; k<n.edges.length; k++) {
903            if(n.edges[k][1]>0)
904              try {
905                if( indexOfElementInLevel(n.edges[k][0], levels[i+1]) >= uidx) {
906                  edgeOcrnce[n.edges[k][0]]=1;
907                }
908              }
909              catch(Exception ex) {
910                ex.printStackTrace();
911              }
912          }
913          for(int k=0; k<levels[i+1].length; k++) {
914            if(edgeOcrnce[levels[i+1][k]]==1) {
915              MyListNode temp = new MyListNode(levels[i+1][k]); //new MyListNode(n.edges[k][0]);
916              lower.add(temp);
917              lastOcrnce[levels[i+1][k]] = temp;
918              edgeOcrnce[levels[i+1][k]] = 0;
919              //System.out.println("Adding to lower: "+levels[i+1][k]+
920              //" which is: "+((GraphNode)m_nodes.elementAt(levels[i+1][k])).ID+
921              //" first's n is: "+lower.first.n);
922            }
923           
924          }
925          uidx++;
926        }
927        else {
928          int k1=0, k2=0, k3=0;
929          GraphNode n = (GraphNode) m_nodes.elementAt(levels[i+1][lidx]);
930          //Deactivating and counting crossings for all edges ending in it
931          //coming from up and upper left
932          if(lastOcrnce[levels[i+1][lidx]]!=null) {
933           
934            MyListNode temp = new MyListNode(-1); temp.next = lower.first;
935            try {
936              do {
937                temp = temp.next;
938                if(levels[i+1][lidx]==temp.n) {
939                  k1 = k1+1;
940                  k3 = k3+k2;
941                  lower.remove(temp);
942                  //System.out.println("Removing from lower: "+temp.n);
943                }
944                else
945                  k2 = k2+1;
946                //System.out.println("temp: "+temp+" lastOcrnce: "+
947                //                   lastOcrnce[levels[i+1][lidx]]+" temp.n: "+
948                //                   temp.n+" lastOcrnce.n: "+
949                //                   lastOcrnce[levels[i+1][lidx]].n);
950              } while(temp!=lastOcrnce[levels[i+1][lidx]]);
951            }
952            catch(NullPointerException ex) {
953              System.out.print("levels[i+1][lidx]: "+levels[i+1][lidx]+
954              " which is: "+
955              ((GraphNode)m_nodes.elementAt(levels[i+1][lidx])).ID+
956              " temp: "+temp);
957              System.out.println(" lower.first: "+lower.first);
958              ex.printStackTrace();
959              System.exit(-1); 
960            }
961           
962            lastOcrnce[levels[i+1][lidx]]=null;
963            sum = sum + k1*upper.size() + k3;
964          }
965         
966          //Activating all the edges going out towards the upper right
967          for(int k=0; k<n.edges.length; k++) {
968            if(n.edges[k][1]<0)
969              try {
970                if( indexOfElementInLevel(n.edges[k][0], levels[i]) > lidx) {
971                  edgeOcrnce[n.edges[k][0]]=1;
972                }
973              }
974              catch(Exception ex) {
975                ex.printStackTrace();
976              }
977          }
978          for(int k=0; k<levels[i].length; k++) {
979            if(edgeOcrnce[levels[i][k]]==1) {
980              MyListNode temp = new MyListNode(levels[i][k]);
981              upper.add(temp);
982              lastOcrnce[levels[i][k]]=temp;
983              edgeOcrnce[levels[i][k]]=0;
984              //System.out.println("Adding to upper: "+levels[i][k]+
985              //               " which is : "+
986              //                ((GraphNode)m_nodes.elementAt(levels[i][k])).ID+
987              //               " from node: "+n.ID+", "+k+
988              //               " first's value: "+upper.first.n);
989            }
990          }
991          lidx++;
992        }
993      }
994      //System.out.println("Sum at the end is: "+sum);
995    }
996   
997    return sum;
998  }
999 
1000 
1001  /**
1002   * The following two methods remove cycles from the graph.
1003   */
1004  protected void removeCycles() {
1005    //visited[x]=1 is only  visited AND visited[x]=2 means node is visited
1006    // and is on the current path
1007    int visited[]  = new int[m_nodes.size()];
1008   
1009    for(int i=0; i<graphMatrix.length; i++) {
1010      if(visited[i]==0){
1011        removeCycles2(i, visited);
1012        visited[i]=1;
1013      }
1014    }
1015  }
1016 
1017  /** This method should not be called directly. It should be called only from
1018      to call removeCycles() */
1019  private void removeCycles2(int nindex, int visited[]) {
1020    visited[nindex]=2;
1021    for(int i=0; i<graphMatrix[nindex].length; i++) {
1022      if(graphMatrix[nindex][i]==DIRECTED)
1023        if(visited[i]==0) {
1024          removeCycles2(i, visited);
1025          visited[i]=1;
1026        }
1027        else if(visited[i]==2) {
1028          if(nindex==i) {
1029            graphMatrix[nindex][i]=0;
1030          }
1031          else if(graphMatrix[i][nindex]==DIRECTED) {
1032            //System.out.println("\nFound double "+nindex+','+i);
1033            graphMatrix[i][nindex]=DOUBLE;
1034            graphMatrix[nindex][i]=-DOUBLE;
1035          }
1036          else {
1037            //System.out.println("\nReversing "+nindex+','+i);
1038            graphMatrix[i][nindex]=REVERSED;
1039            graphMatrix[nindex][i]=-REVERSED;
1040          }
1041        }
1042    }
1043  }
1044 
1045  /**
1046   * This method assigns a vertical level to each node.
1047   * See makeProperHierarchy() to see how to use it.
1048   */
1049  protected void assignLevels(int levels[], int depth, int i, int j) {
1050    //System.out.println(i+","+j);
1051    if(i>=graphMatrix.length)
1052      return;
1053    else if(j>=graphMatrix[i].length)
1054      return;
1055    if(graphMatrix[i][j]<=0)
1056      assignLevels(levels, depth, i, ++j);
1057    else if(graphMatrix[i][j]==DIRECTED || graphMatrix[i][j]==DOUBLE) {
1058      if(depth+1>levels[j]) {
1059        levels[j]=depth+1;
1060        assignLevels(levels, depth+1, j, 0);
1061      }
1062      assignLevels(levels, depth, i, ++j);
1063    }
1064  }
1065 
1066 
1067  /**
1068   * This method minimizes the number of edge crossings using the BaryCenter
1069   * heuristics given by Sugiyama et al. 1981
1070   * This method processes the graph topdown if reversed is false,
1071   * otherwise it does bottomup.
1072   */
1073  private int[][] minimizeCrossings(boolean reversed, int nodeLevels[][]) {
1074   
1075    //Minimizing crossings using Sugiyama's method
1076    if(reversed==false) {
1077      for(int times=0; times<1; times++) {
1078        int tempLevels[][] = new int[nodeLevels.length][];
1079       
1080        //System.out.println("---------------------------------");
1081        //System.out.println("Crossings before PHaseID: "+
1082        //                   crossings(nodeLevels));
1083        copy2DArray(nodeLevels, tempLevels);
1084        for(int i=0; i<nodeLevels.length-1; i++)   //Down
1085          phaseID(i, tempLevels);
1086        if(crossings(tempLevels)<crossings(nodeLevels))
1087          nodeLevels = tempLevels;
1088       
1089        //System.out.println("\nCrossings before PHaseIU: "+
1090        //                   crossings(nodeLevels));
1091        tempLevels = new int[nodeLevels.length][];
1092        copy2DArray(nodeLevels, tempLevels);
1093        for(int i=nodeLevels.length-2; i>=0; i--)  //Up
1094          phaseIU(i, tempLevels);
1095        if(crossings(tempLevels)<crossings(nodeLevels))
1096          nodeLevels = tempLevels;
1097       
1098        //System.out.println("\nCrossings before PHaseIID: "+
1099        //                   crossings(nodeLevels));
1100        tempLevels = new int[nodeLevels.length][];
1101        copy2DArray(nodeLevels, tempLevels);
1102        for(int i=0; i<nodeLevels.length-1; i++) {   //Down
1103          phaseIID(i, tempLevels);
1104        }
1105        if(crossings(tempLevels)<crossings(nodeLevels))
1106          nodeLevels = tempLevels;
1107        //System.out.println("Crossings temp:"+crossings(tempLevels)+
1108        //                   " graph:"+crossings(nodeLevels));
1109        //printMatrices(nodeLevels);
1110       
1111        //System.out.println("\nCrossings before PHaseIIU: "+
1112        //                   crossings(nodeLevels));
1113        tempLevels = new int[nodeLevels.length][];
1114        copy2DArray(nodeLevels, tempLevels);
1115        for(int i=nodeLevels.length-2; i>=0; i--) {   //Up
1116          phaseIIU(i, tempLevels);
1117        }
1118        if(crossings(tempLevels)<crossings(nodeLevels))
1119          nodeLevels = tempLevels;
1120        ///System.out.println("Crossings temp:"+crossings(tempLevels)+
1121        //                    " graph:"+crossings(nodeLevels));
1122        ///printMatrices(nodeLevels);
1123        //System.out.println("\nCrossings after phaseIIU: "+
1124        //                   crossings(nodeLevels));
1125      }
1126      return nodeLevels;
1127    }
1128    else {
1129      for(int times=0; times<1; times++) {
1130        int tempLevels[][] = new int[nodeLevels.length][];
1131       
1132        //System.out.println("---------------------------------");
1133        //System.out.println("\nCrossings before PHaseIU: "+
1134        //                   crossings(nodeLevels));
1135        copy2DArray(nodeLevels, tempLevels);
1136        for(int i=nodeLevels.length-2; i>=0; i--)  //Up
1137          phaseIU(i, tempLevels);
1138        if(crossings(tempLevels)<crossings(nodeLevels))
1139          nodeLevels = tempLevels;
1140        //printMatrices(nodeLevels);
1141       
1142        //System.out.println("Crossings before PHaseID: "+
1143        //                   crossings(nodeLevels));
1144        tempLevels = new int[nodeLevels.length][];
1145        copy2DArray(nodeLevels, tempLevels);
1146        for(int i=0; i<nodeLevels.length-1; i++)   //Down
1147          phaseID(i, tempLevels);
1148        if(crossings(tempLevels)<crossings(nodeLevels))
1149          nodeLevels = tempLevels;
1150        ///printMatrices(nodeLevels);
1151       
1152        //System.out.println("\nCrossings before PHaseIIU: "+
1153        //                   crossings(nodeLevels));
1154        tempLevels = new int[nodeLevels.length][];
1155        copy2DArray(nodeLevels, tempLevels);
1156        for(int i=nodeLevels.length-2; i>=0; i--) {   //Up
1157          phaseIIU(i, tempLevels);
1158        }
1159        if(crossings(tempLevels)<crossings(nodeLevels))
1160          nodeLevels = tempLevels;
1161        //printMatrices(nodeLevels);
1162       
1163        //System.out.println("\nCrossings before PHaseIID: "+
1164        //                   crossings(nodeLevels));
1165        tempLevels = new int[nodeLevels.length][];
1166        copy2DArray(nodeLevels, tempLevels);
1167        for(int i=0; i<nodeLevels.length-1; i++) {   //Down
1168          phaseIID(i, tempLevels);
1169        }
1170        if(crossings(tempLevels)<crossings(nodeLevels))
1171          nodeLevels = tempLevels;
1172        ///printMatrices(nodeLevels);
1173        //System.out.println("\nCrossings after phaseIID: "+
1174        //                   crossings(nodeLevels));
1175      }
1176      return nodeLevels;
1177    }
1178  }
1179 
1180 
1181  /**
1182   * See Sugiyama et al. 1981 (full reference give at top)
1183   * lindex is the index of the level we want to process.
1184   * In this method we'll sort the vertices at the level one
1185   * below lindex according to their UP-barycenters (or column
1186   * barycenters).
1187   */
1188  protected void phaseID(final int lindex, final int levels[][]) {
1189    float colBC[]; //= new float[levels[lindex+1].size()];
1190    colBC = calcColBC(lindex, levels);
1191   
1192    //System.out.println("In ID Level"+(lindex+1)+":");
1193    //System.out.print("\t");
1194    //for(int i=0; i<colBC.length; i++)
1195    //   {System.out.print("Col"+(i+1)+":"+colBC[i]+" ");
1196    //    }
1197    //System.out.println("");
1198    //colBC = calcColBC1(lindex, levels);
1199    //for(int i=0; i<colBC.length; i++)
1200    //  {System.out.print("Col"+(i+1)+":"+colBC[i]+" ");
1201    //    }
1202    //System.out.println("");
1203    //System.out.print("\n\tNodes ");
1204    //for(int i=0; i<levels[lindex+1].length; i++)
1205    //    System.out.print(levels[lindex+1][i]+" ");
1206    //System.out.println("");
1207    //System.out.println("\nCrossings: "+crossings(levels));
1208    //inspect(false, lindex, levels, colBC);
1209   
1210    isort(levels[lindex+1], colBC);
1211    //combSort11(levels[lindex+1], colBC);
1212    //System.out.println("After sorting");
1213    //System.out.print("\t");
1214    //for(int i=0; i<colBC.length; i++)
1215    //    {System.out.print("Col"+(i+1)+":"+colBC[i]+" ");
1216    //    }
1217    //System.out.print("\n\tNodes ");
1218    //for(int i=0; i<levels[lindex+1].length; i++)
1219    //    System.out.print(levels[lindex+1][i]+" ");
1220    //System.out.println("\nCrossings: "+crossings(levels));
1221    ///System.out.println("");
1222  }
1223 
1224  /**
1225   * See Sugiyama et al. 1981 (full reference give at top)
1226   * lindex is the index of the level we want to process.
1227   * In this method we'll sort the vertices at the level
1228   * lindex according to their DOWN-barycenters (or row
1229   * barycenters).
1230   */
1231  public void phaseIU(final int lindex, final int levels[][]) {
1232    float rowBC[];
1233    rowBC = calcRowBC(lindex, levels);
1234   
1235    //System.out.println("In IU Level"+(lindex+1)+":");
1236    //System.out.print("\t");
1237    //for(int i=0; i<rowBC.length; i++)
1238    //    {System.out.print("Row"+(i+1)+":"+rowBC[i]+" ");
1239    //    }
1240    //    System.out.print("\n\t");
1241    //    rowBC = calcRowBC1(lindex, levels);
1242    //    for(int i=0; i<rowBC.length; i++)
1243    //      {System.out.print("Row"+(i+1)+":"+rowBC[i]+" ");
1244    //      }
1245    //    System.out.println("");
1246    //System.out.print("\n\tNodes ");
1247    //for(int i=0; i<levels[lindex].length; i++)
1248    //    System.out.print(levels[lindex][i]+" ");
1249    //System.out.println("\nCrossings: "+crossings(levels));
1250    //inspect(true, lindex, levels, rowBC);
1251   
1252    isort(levels[lindex], rowBC);
1253    //combSort11(levels[lindex], rowBC);
1254    //System.out.println("After sorting\n\t");
1255    //for(int i=0; i<rowBC.length; i++)
1256    //    {System.out.print("Row"+(i+1)+":"+rowBC[i]+" ");
1257    //    }
1258    //System.out.print("\n\tNodes ");
1259    //for(int i=0; i<levels[lindex].length; i++)
1260    //    System.out.print(levels[lindex][i]+" ");
1261    //System.out.println("\nCrossings: "+crossings(levels));
1262  }
1263 
1264 
1265  /**
1266   * See Sugiyama et al. 1981 (full reference give at top)
1267   */
1268  public void phaseIID(final int lindex, final int levels[][]) {
1269    float colBC[];
1270    colBC = calcColBC(lindex, levels);
1271   
1272    //System.out.println("getting into phase IID");
1273    for(int i=0; i<colBC.length-1; i++) {
1274      if(colBC[i]==colBC[i+1]) {
1275        //System.out.println("Crossings before begining of iteration: "+
1276        //                   crossings(levels));
1277        int tempLevels[][] = new int[levels.length][];
1278        copy2DArray(levels, tempLevels);
1279        //System.out.println("Interchanging: "+
1280        //       ((GraphNode)m_nodes.elementAt(levels[lindex+1][i])).ID+
1281        //       " & "+
1282        //       ((GraphNode)m_nodes.elementAt(levels[lindex+1][(i+1)])).ID+
1283        //       " at level "+(lindex+1) );
1284        int node1 = levels[lindex+1][i];
1285        int node2 = levels[lindex+1][i+1];
1286        levels[lindex+1][i+1] = node1;
1287        levels[lindex+1][i] = node2;
1288       
1289        for(int k=lindex+1; k<levels.length-1; k++)
1290          phaseID(k, levels);
1291        //System.out.println("Crossings temp:"+crossings(tempLevels)+
1292        //                   " graph:"+crossings(levels));
1293        if(crossings(levels)<=crossings(tempLevels)) {
1294          //System.out.println("Crossings temp: "+crossings(tempLevels)+
1295          //                   " Crossings levels: "+crossings(levels));
1296          copy2DArray(levels, tempLevels); } //printMatrices(levels); }
1297        else {
1298          copy2DArray(tempLevels, levels);
1299          levels[lindex+1][i+1] = node1;
1300          levels[lindex+1][i] = node2;
1301        }
1302        //System.out.println("Crossings after PhaseID of phaseIID, "+
1303        //                   "in iteration "+i+" of "+(colBC.length-1)+" at "+
1304        //                   lindex+", levels: "+crossings(levels)+
1305        //                   " temp: "+crossings(tempLevels));
1306       
1307        //tempLevels = new int[levels.length][];
1308        //copy2DArray(levels, tempLevels);
1309        for(int k=levels.length-2; k>=0; k--)
1310          phaseIU(k, levels);
1311        //System.out.println("Crossings temp:"+crossings(tempLevels)+
1312        //                   " graph:"+crossings(levels));
1313        //if(crossings(tempLevels)<crossings(levels)) {
1314        // System.out.println("Crossings temp: "+crossings(tempLevels)+
1315        //                    " Crossings levels: "+crossings(levels));
1316        //      copy2DArray(tempLevels, levels); } //printMatrices(levels); }
1317        if(crossings(tempLevels)<crossings(levels))
1318          copy2DArray(tempLevels, levels);
1319       
1320        //System.out.println("Crossings after PhaseIU of phaseIID, in"+
1321        //                   " iteration "+i+" of "+(colBC.length-1)+" at "
1322        //                   +lindex+", levels: "+crossings(levels)+" temp: "+
1323        //                   crossings(tempLevels));
1324        //colBC = calcColBC(lindex, levels);
1325      }
1326    }
1327  }
1328 
1329 
1330  /**
1331   * See Sugiyama et al. 1981 (full reference give at top)
1332   */
1333  public void phaseIIU(final int lindex, final int levels[][]) {
1334    float rowBC[];
1335    rowBC = calcRowBC(lindex, levels);
1336   
1337    //System.out.println("Getting into phaseIIU");
1338    for(int i=0; i<rowBC.length-1; i++) {
1339      if(rowBC[i]==rowBC[i+1]) {
1340        //System.out.println("Crossings before begining of iteration: "+
1341        //                   crossings(levels));
1342        int tempLevels[][] = new int[levels.length][];
1343        copy2DArray(levels, tempLevels);
1344        //System.out.println("Interchanging: "+
1345        //          ((GraphNode)m_nodes.elementAt(levels[lindex][i])).ID+" & "+
1346        //          ((GraphNode)m_nodes.elementAt(levels[lindex][i+1])).ID+
1347        //          " at level "+(lindex+1) );
1348        int node1 = levels[lindex][i];
1349        int node2 = levels[lindex][i+1];
1350        levels[lindex][i+1] = node1;
1351        levels[lindex][i] = node2;
1352       
1353        for(int k=lindex-1; k>=0; k--)
1354          phaseIU(k, levels);
1355        if(crossings(levels)<=crossings(tempLevels)) { 
1356          //System.out.println("Crossings temp: "+crossings(tempLevels)+
1357          //                   " Crossings levels: "+crossings(levels));
1358          copy2DArray(levels, tempLevels); } //printMatrices(levels);
1359        else {
1360          copy2DArray(tempLevels, levels);
1361          levels[lindex][i+1] = node1;
1362          levels[lindex][i] = node2;
1363        }
1364        //System.out.println("Crossings after PhaseIU of PhaseIIU, in "+
1365        //                   "iteration "+i+" of "+(rowBC.length-1)+" at "
1366        //                   +lindex+", levels: "+crossings(levels)+
1367        //                   " temp: "+crossings(tempLevels));
1368       
1369        //tempLevels = new int[levels.length][];
1370        //copy2DArray(levels, tempLevels);
1371        for(int k=0; k<levels.length-1; k++) //lindex-1; k++)
1372          phaseID(k, levels);
1373        //if(crossings(tempLevels)<crossings(levels)) {
1374        //  System.out.println("Crossings temp: "+crossings(tempLevels)+
1375        //                     " Crossings levels: "+crossings(levels));
1376        //      copy2DArray(tempLevels, levels); } //printMatrices(levels); }
1377        if(crossings(tempLevels)<=crossings(levels))
1378          copy2DArray(tempLevels, levels);
1379        //System.out.println("Crossings after PhaseID of phaseIIU, in "+
1380        //                   "iteration "+i+" of "+(rowBC.length-1)+" at "
1381        //                   +lindex+", levels: "+crossings(levels)+
1382        //                   " temp: "+crossings(tempLevels));
1383        //rowBC = calcRowBC(lindex, levels);
1384      }
1385    }
1386  }
1387 
1388 
1389  /**
1390   * See Sugiyama et al. 1981 (full reference give at top)
1391   */
1392  protected float [] calcRowBC(final int lindex, final int levels[][]){
1393    float rowBC[] = new float[levels[lindex].length];
1394    GraphNode n;
1395   
1396    for(int i=0; i<levels[lindex].length; i++) {
1397      int sum=0;
1398      n = (GraphNode)m_nodes.elementAt(levels[lindex][i]);
1399     
1400      for(int j=0; j<n.edges.length; j++) {
1401        if(n.edges[j][1]>0) {
1402          sum++;
1403          try {
1404            rowBC[i] = 
1405              rowBC[i]+indexOfElementInLevel(n.edges[j][0], levels[lindex+1])+1;
1406          }
1407          catch(Exception ex) { return null; }
1408        }
1409      }
1410      if(rowBC[i]!=0)
1411        rowBC[i] = rowBC[i]/sum;
1412    }
1413    return rowBC;
1414  }
1415 
1416 
1417  /**
1418   * See Sugiyama et al. 1981 (full reference give at top)
1419   */
1420  protected float [] calcColBC(final int lindex, final int levels[][]) {
1421    float colBC[] = new float[levels[lindex+1].length];
1422    GraphNode n;
1423   
1424    for(int i=0; i<levels[lindex+1].length; i++) {
1425      int sum=0;
1426      n = (GraphNode)m_nodes.elementAt(levels[lindex+1][i]);
1427     
1428      for(int j=0; j<n.edges.length; j++) {
1429        if(n.edges[j][1]<1) {
1430          sum++;
1431          try{
1432            colBC[i] =
1433                colBC[i]+indexOfElementInLevel(n.edges[j][0], levels[lindex])+1;
1434          }
1435          catch(Exception ex) { return null; }
1436        }
1437      }
1438      if(colBC[i]!=0)
1439        colBC[i]=colBC[i]/sum;
1440    }
1441    return colBC;
1442  }
1443 
1444  /**
1445   * Prints out the interconnection matrix at each level.
1446   * See Sugiyama et al. 1981 (full reference give at top)
1447   */
1448  protected void printMatrices(final int levels[][]) {
1449    int i=0;
1450    for(i=0; i<levels.length-1; i++) {
1451      float rowBC[]=null; float colBC[]=null;
1452      try{
1453        rowBC = calcRowBC(i, levels); colBC = calcColBC(i, levels);
1454      }
1455      catch(NullPointerException ne) {
1456        System.out.println("i: "+i+" levels.length: "+levels.length);
1457        ne.printStackTrace();
1458        return;
1459      }
1460     
1461      System.out.print("\nM"+(i+1)+"\t");
1462      for(int j=0; j<levels[i+1].length; j++) {
1463        System.out.print( ((GraphNode)m_nodes.elementAt(levels[i+1][j])).ID +
1464                          " ");
1465        //((Integer)levels[i+1].elementAt(j)).intValue())+" ");
1466      }
1467      System.out.println("");
1468     
1469      for(int j=0; j<levels[i].length; j++) {
1470        System.out.print( ((GraphNode)m_nodes.elementAt(levels[i][j])).ID+"\t");
1471        //((Integer)levels[i].elementAt(j)).intValue())+"\t");
1472        for(int k=0; k<levels[i+1].length; k++) {
1473         
1474          System.out.print(graphMatrix[levels[i][j]] 
1475                                 //((Integer)levels[i].elementAt(j)).intValue()]
1476                                      [levels[i+1][k]]+" "); 
1477                         //((Integer)levels[i+1].elementAt(k)).intValue()]+" ");
1478         
1479        }
1480        System.out.println(rowBC[j]);
1481      }
1482      System.out.print("\t");
1483      for(int k=0; k<levels[i+1].length; k++)
1484        System.out.print(colBC[k]+" ");
1485    }
1486    System.out.println("\nAt the end i: "+i+" levels.length: "+levels.length);
1487  }
1488 
1489  /**
1490   * This methods sorts the vertices in level[] according to their
1491   * barycenters in BC[], using combsort11. It, however, doesn't touch the
1492   * vertices with barycenter equal to zero.
1493   */
1494    /*
1495     *  //This method should be removed
1496     protected static void combSort11(int level[], float BC[]) { 
1497        int switches, j, top, gap, lhold;
1498        float hold;
1499        gap = BC.length;
1500        do {
1501            gap=(int)(gap/1.3);
1502            switch(gap) {
1503            case 0:
1504                gap = 1;
1505                break;
1506            case 9:
1507            case 10:
1508                gap=11;
1509                break;
1510            default:
1511                break;
1512            }
1513            switches=0;
1514            top = BC.length-gap;
1515            for(int i=0; i<top; i++) {
1516                j=i+gap;
1517                if(BC[i]==0 || BC[j]==0)
1518                    continue;
1519                if(BC[i] > BC[j]) {
1520                    hold=BC[i];
1521                    BC[i]=BC[j];
1522                    BC[j]=hold;
1523                    lhold = level[i];
1524                    level[i] = level[j];
1525                    level[j] = lhold;
1526                    switches++;
1527                }//endif
1528            }//endfor
1529        }while(switches>0 || gap>1);
1530    }
1531     */
1532 
1533 
1534  /**
1535   * This methods sorts the vertices in level[] according to their
1536   * barycenters in BC[], using insertion sort. It, however, doesn't touch the
1537   * vertices with barycenter equal to zero.
1538   */
1539   //Both level and BC have elements in the same order
1540  protected static void isort(int level[], float BC[]) { 
1541    float temp;
1542    int temp2;
1543    for(int i=0; i<BC.length-1; i++) {
1544     
1545      int j=i;
1546      temp=BC[j+1];
1547      temp2=level[j+1];
1548      if(temp==0)
1549        continue;
1550      int prej=j+1;
1551     
1552      while( j>-1 && (temp<BC[j]|| BC[j]==0) ) {
1553        if(BC[j]==0){
1554          j--; continue;}
1555        else {
1556          BC[prej] = BC[j];
1557          level[prej] = level[j];
1558          prej=j;
1559          j--;
1560        }
1561      }
1562      //j++;
1563      BC[prej]    = temp;
1564      level[prej] = temp2;
1565      //Integer node = (Integer)level.elementAt(i+1);
1566      //level.removeElementAt(i+1);
1567      //level.insertElementAt(node, prej);
1568    }
1569  }
1570 
1571 
1572  /**
1573   * Copies one Matrix of type int[][] to another.
1574   */
1575  protected void copyMatrix(int from[][], int to[][]) {
1576    for(int i=0; i<from.length; i++)
1577      for(int j=0; j<from[i].length; j++)
1578        to[i][j]=from[i][j];
1579  }
1580 
1581  /**
1582   * Copies one array of type int[][] to another.
1583   */
1584  protected void copy2DArray(int from[][], int to[][]) {
1585    for(int i=0; i<from.length; i++) {
1586      to[i] = new int[from[i].length];
1587      System.arraycopy(from[i], 0, to[i], 0, from[i].length);
1588      //for(int j=0; j<from[i].length; j++)
1589      //        to[i][j] = from[i][j];
1590    }
1591  }
1592 
1593  /**
1594   * This method lays out the vertices horizontally, in each level.
1595   * It simply assings an x value to a vertex according to its
1596   * index in the level.
1597   */
1598  protected void naiveLayout() {
1599    /*
1600    if(maxStringWidth==0) {
1601      int strWidth;
1602      for(int i=0; i<m_nodes.size(); i++) {
1603        strWidth = m_fm.stringWidth(((GraphNode)m_nodes.elementAt(i)).lbl);
1604        if(strWidth>maxStringWidth)
1605          maxStringWidth=strWidth;
1606      }
1607     
1608      if(m_nodeSize<maxStringWidth)
1609      {m_nodeSize = maxStringWidth+4; m_nodeArea = m_nodeSize+8; }
1610    }
1611    */
1612    if(nodeLevels==null)
1613      makeProperHierarchy();
1614   
1615    //int nodeHeight = m_nodeHeight*2; //m_fm.getHeight()*2;
1616    for(int i=0, temp=0; i<nodeLevels.length; i++) {
1617      for(int j=0; j<nodeLevels[i].length; j++) {
1618        temp=nodeLevels[i][j];
1619        //horPositions[temp]=j;
1620        GraphNode n = (GraphNode)m_nodes.elementAt(temp);
1621        n.x = j*m_nodeWidth; //horPositions[temp]*m_nodeWidth;
1622        n.y = i*3*m_nodeHeight;
1623      }
1624    }
1625    //setAppropriateSize();
1626  }
1627 
1628 
1629  protected int uConnectivity(int lindex, int eindex) {
1630    int n=0;
1631    for(int i=0; i<nodeLevels[lindex-1].length; i++)
1632      if(graphMatrix[ nodeLevels[lindex-1][i] ][ nodeLevels[lindex][eindex] ]>0)
1633        n++;
1634   
1635    return n;
1636  }
1637 
1638  protected int lConnectivity(int lindex, int eindex) {
1639    int n=0;
1640    for(int i=0; i<nodeLevels[lindex+1].length; i++)
1641      if(graphMatrix[ nodeLevels[lindex][eindex] ][ nodeLevels[lindex+1][i] ]>0)
1642        n++;
1643   
1644    return n;
1645  }
1646 
1647  protected int uBCenter(int lindex, int eindex, int horPositions[]) {
1648    int sum=0;
1649   
1650    for(int i=0; i<nodeLevels[lindex-1].length; i++)
1651      if(graphMatrix[nodeLevels[lindex-1][i]][nodeLevels[lindex][eindex]]>0)
1652        sum = sum + (horPositions[nodeLevels[lindex-1][i]]);
1653    if(sum!=0) { // To avoid 0/0
1654      //System.out.println("uBC Result: "+sum+"/"+
1655      //                   uConnectivity(lindex,eindex)+
1656      //                   " = "+(sum/uConnectivity(lindex,eindex)) );
1657      sum = sum/uConnectivity(lindex,eindex);
1658    }
1659    return sum;
1660  }
1661 
1662 
1663  protected int lBCenter(int lindex, int eindex, int horPositions[]) {
1664    int sum=0;
1665   
1666    for(int i=0; i<nodeLevels[lindex+1].length; i++)
1667      if(graphMatrix[nodeLevels[lindex][eindex]][nodeLevels[lindex+1][i]]>0)
1668        sum = sum + (horPositions[nodeLevels[lindex+1][i]]);
1669    if(sum!=0)  // To avoid 0/0
1670      sum = sum/lConnectivity(lindex, eindex); //lConectivity;
1671    return sum;
1672  }
1673 
1674  private void tempMethod(int horPositions[]) {
1675   
1676    int minPosition = horPositions[0];
1677   
1678    for(int i=0; i<horPositions.length; i++)
1679      if(horPositions[i]<minPosition)
1680        minPosition=horPositions[i];
1681    if(minPosition<0) {
1682      minPosition = minPosition*-1;
1683      for(int i=0; i<horPositions.length; i++){
1684        //System.out.print(horPositions[i]);
1685        horPositions[i]+=minPosition;
1686        //System.out.println(">"+horPositions[i]);
1687      }
1688    }
1689   
1690    //int nodeHeight = m_nodeHeight*2; //m_fm.getHeight()*2;
1691    for(int i=0, temp=0; i<nodeLevels.length; i++) {
1692      for(int j=0; j<nodeLevels[i].length; j++) {
1693        temp=nodeLevels[i][j];
1694        //horPositions[temp]=j;
1695        GraphNode n = (GraphNode)m_nodes.elementAt(temp);
1696        n.x = horPositions[temp]*m_nodeWidth;
1697        n.y = i*3*m_nodeHeight;
1698      }
1699    }
1700  }
1701 
1702  /**
1703   * This method lays out the vertices horizontally, in each level.
1704   * See Sugiyama et al. 1981 for full reference.
1705   */
1706  protected void priorityLayout1() {
1707   
1708    int [] horPositions = new int[m_nodes.size()];
1709    int maxCount=0;
1710   
1711    for(int i=0; i<nodeLevels.length; i++) {
1712      int count=0;
1713      for(int j=0; j<nodeLevels[i].length; j++) {
1714        horPositions[nodeLevels[i][j]]=j;
1715        count++;
1716      }
1717      if(count>maxCount)
1718        maxCount=count;
1719    }
1720    //fireLayoutCompleteEvent( new LayoutCompleteEvent(this) );
1721    int priorities[], BC[];
1722    //System.out.println("********Going from 2 to n********");
1723    for(int i=1; i<nodeLevels.length; i++) {
1724      priorities = new int[nodeLevels[i].length];
1725      BC = new int[nodeLevels[i].length];
1726      for(int j=0; j<nodeLevels[i].length; j++) {
1727        if(((GraphNode)m_nodes.elementAt(nodeLevels[i][j])).ID.startsWith("S"))
1728          priorities[j] = maxCount+1;
1729        else
1730          priorities[j] = uConnectivity(i, j);
1731        BC[j] = uBCenter(i, j, horPositions);
1732      }
1733      //for(int j=0; j<nodeLevels[i].length; j++)
1734      //  System.out.println("Level: "+(i+1)+" Node: "
1735      //        +((GraphNode)m_nodes.elementAt(nodeLevels[i][j])).ID
1736      //        +" uConnectivity: "+priorities[j]+" uBC: "+BC[j]+" position: "
1737      //        +horPositions[nodeLevels[i][j]]);
1738      priorityLayout2(nodeLevels[i], priorities, BC, horPositions);
1739      //repaint
1740      //try {
1741      //        tempMethod(horPositions);
1742      //        fireLayoutCompleteEvent( new LayoutCompleteEvent(this) );
1743      //        Thread.sleep(1000);
1744      //} catch(InterruptedException ie) { ie.printStackTrace(); }
1745     
1746      //for(int j=0; j<nodeLevels[i].length; j++)
1747      //    System.out.println("Level: "+(i+1)+" Node: "
1748      //        +((GraphNode)m_nodes.elementAt(nodeLevels[i][j])).ID
1749      //        +" uConnectivity: "+priorities[j]+" uBC: "+BC[j]+" position: "
1750      //        +horPositions[nodeLevels[i][j]]);
1751    }
1752   
1753    //System.out.println("********Going from n-1 to 1********");
1754    for(int i=nodeLevels.length-2; i>=0; i--) {
1755      priorities = new int[nodeLevels[i].length];
1756      BC = new int[nodeLevels[i].length];
1757      for(int j=0; j<nodeLevels[i].length; j++) {
1758        if(((GraphNode)m_nodes.elementAt(nodeLevels[i][j])).ID.startsWith("S"))
1759          priorities[j] = maxCount+1;
1760        else
1761          priorities[j] = lConnectivity(i, j);
1762        BC[j] = lBCenter(i, j, horPositions); //, priorities[j]);
1763      }
1764      priorityLayout2(nodeLevels[i], priorities, BC, horPositions);
1765      //repaint();
1766      //try {
1767      //        tempMethod(horPositions);
1768      //        fireLayoutCompleteEvent( new LayoutCompleteEvent(this) );
1769      //        Thread.sleep(1000);
1770      //} catch(InterruptedException ie) { ie.printStackTrace(); }
1771     
1772      //for(int j=0; j<nodeLevels[i].length; j++)
1773      //    System.out.println("Level: "+(i+1)+" Node: "
1774      //        +((GraphNode)m_nodes.elementAt(nodeLevels[i][j])).ID
1775      //        +" lConnectivity: "+priorities[j]+" lBC: "+BC[j]+" position: "
1776      //        +horPositions[nodeLevels[i][j]]);
1777    }
1778   
1779    //System.out.println("********Going from 2 to n again********");
1780    for(int i=2; i<nodeLevels.length; i++) {
1781      priorities = new int[nodeLevels[i].length];
1782      BC = new int[nodeLevels[i].length];
1783      for(int j=0; j<nodeLevels[i].length; j++) {
1784        if(((GraphNode)m_nodes.elementAt(nodeLevels[i][j])).ID.startsWith("S"))
1785          priorities[j] = maxCount+1;
1786        else
1787          priorities[j] = uConnectivity(i, j);
1788        BC[j] = uBCenter(i, j, horPositions);
1789      }
1790      //for(int j=0; j<nodeLevels[i].length; j++)
1791      //    System.out.println("Level: "+(i+1)+" Node: "
1792      //        +((GraphNode)m_nodes.elementAt(nodeLevels[i][j])).ID
1793      //        +" uConnectivity: "+priorities[j]+" uBC: "+BC[j]+" position: "
1794      //        +horPositions[nodeLevels[i][j]]);
1795      priorityLayout2(nodeLevels[i], priorities, BC, horPositions);
1796      //repaint();
1797      //try {
1798      //        tempMethod(horPositions);
1799      //        fireLayoutCompleteEvent( new LayoutCompleteEvent(this) );
1800      //        Thread.sleep(1000);
1801      //} catch(InterruptedException ie) { ie.printStackTrace(); }
1802      //for(int j=0; j<nodeLevels[i].length; j++)
1803      //    System.out.println("Level: "+(i+1)+" Node: "
1804      //        +((GraphNode)m_nodes.elementAt(nodeLevels[i][j])).ID
1805      //        +" uConnectivity: "+priorities[j]+" uBC: "+BC[j]+" position: "
1806      //        +horPositions[nodeLevels[i][j]]);
1807    }
1808   
1809    int minPosition = horPositions[0];
1810   
1811    for(int i=0; i<horPositions.length; i++)
1812      if(horPositions[i]<minPosition)
1813        minPosition=horPositions[i];
1814    if(minPosition<0) {
1815      minPosition = minPosition*-1;
1816      for(int i=0; i<horPositions.length; i++){
1817        //System.out.print(horPositions[i]);
1818        horPositions[i]+=minPosition;
1819        //System.out.println(">"+horPositions[i]);
1820      }
1821    }
1822   
1823    //int nodeHeight = m_nodeHeight*2; //m_fm.getHeight()*2;
1824    for(int i=0, temp=0; i<nodeLevels.length; i++) {
1825      for(int j=0; j<nodeLevels[i].length; j++) {
1826        temp=nodeLevels[i][j];
1827        //horPositions[temp]=j;
1828        GraphNode n = (GraphNode)m_nodes.elementAt(temp);
1829        n.x = horPositions[temp]*m_nodeWidth;
1830        n.y = i*3*m_nodeHeight;
1831      }
1832    }
1833    //setAppropriateSize();
1834  }
1835 
1836  /**
1837   * This method is used by priorityLayout1(). It should
1838   * not be called directly.
1839   * This method does the actual moving of the vertices in each level
1840   * based on their priorities and barycenters.
1841   */
1842  private void priorityLayout2(int level[], int priorities[], 
1843                               int bCenters[], int horPositions[]) {
1844    int descOrder[] = new int[priorities.length];
1845   
1846    //Getting the indices of priorities in descending order
1847    descOrder[0]=0;
1848    for(int i=0; i<priorities.length-1; i++) {
1849      int j=i;
1850      int temp=i+1;
1851     
1852      while( j>-1 && priorities[descOrder[j]]<priorities[temp] ) {
1853        descOrder[j+1] = descOrder[j];
1854        j--;
1855      }
1856      j++;
1857      descOrder[j] = temp;
1858    }
1859   
1860    //System.out.println("\nPriorities:");
1861    //for(int i=0; i<priorities.length; i++)
1862    //    System.out.print(priorities[i]+" ");
1863    //System.out.println("\nDescOrder:");
1864    //for(int i=0; i<descOrder.length; i++)
1865    //    System.out.print(descOrder[i]+" ");
1866   
1867    for(int k=0; k<descOrder.length; k++)
1868      for(int i=0; i<descOrder.length; i++) {
1869       
1870        int leftCount=0, rightCount=0, leftNodes[], rightNodes[];
1871        for(int j=0; j<priorities.length; j++) {
1872          if( horPositions[level[descOrder[i]]] > horPositions[level[j]] )
1873            leftCount++;
1874          else if( horPositions[level[descOrder[i]]] < horPositions[level[j]] )
1875            rightCount++;
1876        }
1877        leftNodes = new int[leftCount];
1878        rightNodes = new int[rightCount];
1879       
1880        for(int j=0, l=0, r=0; j<priorities.length; j++)
1881          if( horPositions[level[descOrder[i]]] > horPositions[level[j]] )
1882            leftNodes[l++]=j;
1883          else if( horPositions[level[descOrder[i]]] < horPositions[level[j]] )
1884            rightNodes[r++]=j;
1885       
1886       
1887        //****Moving left
1888        while(Math.abs(horPositions[level[descOrder[i]]]-1
1889                                    -bCenters[descOrder[i]])  <
1890          Math.abs(horPositions[level[descOrder[i]]]-bCenters[descOrder[i]]) ) {
1891         
1892          //****Checking if it can be moved to left
1893          int temp = horPositions[level[descOrder[i]]];
1894          boolean cantMove=false;
1895         
1896          for(int j=leftNodes.length-1; j>=0; j--) {
1897            if(temp-horPositions[level[leftNodes[j]]] > 1)
1898              break;
1899            else if(priorities[descOrder[i]]<=priorities[leftNodes[j]])
1900            { cantMove=true; break; }
1901            else
1902              temp = horPositions[level[leftNodes[j]]];
1903          }
1904          //if(horPositions[level[descOrder[i]]]-1==
1905          //   horPositions[level[leftNodes[j]]])
1906          //    cantMove = true;
1907          if(cantMove)
1908            break;
1909         
1910          temp = horPositions[level[descOrder[i]]]-1;
1911          //****moving other vertices to left
1912          for(int j=leftNodes.length-1; j>=0; j--) {
1913            if(temp==horPositions[level[leftNodes[j]]]) {
1914              //System.out.println("Moving "+
1915              //     ((Node)m_nodes.elementAt(level[leftNodes[j]])).ID+" from "
1916              //     +horPositions[level[leftNodes[j]]]+" to "
1917              //     +(horPositions[level[leftNodes[j]]]-1) );
1918              horPositions[level[leftNodes[j]]] = 
1919                                    temp = horPositions[level[leftNodes[j]]]-1; 
1920            }
1921           
1922          }
1923          //System.out.println("Moving main "+
1924          //    ((GraphNode)m_nodes.elementAt(level[descOrder[i]])).ID+" from "
1925          //     +horPositions[level[descOrder[i]]]+" to "
1926          //     +(horPositions[level[descOrder[i]]]-1));
1927          horPositions[level[descOrder[i]]]=horPositions[level[descOrder[i]]]-1;
1928        }
1929       
1930        //****Moving right
1931        while(Math.abs(horPositions[level[descOrder[i]]]+1
1932                                            -bCenters[descOrder[i]])  <
1933          Math.abs(horPositions[level[descOrder[i]]]-bCenters[descOrder[i]]) ) {
1934          //****checking if the vertex can be moved
1935          int temp = horPositions[level[descOrder[i]]];
1936          boolean cantMove=false;
1937         
1938          for(int j=0; j<rightNodes.length; j++) {
1939            if(horPositions[level[rightNodes[j]]]-temp > 1)
1940              break;
1941            else if(priorities[descOrder[i]]<=priorities[rightNodes[j]])
1942            { cantMove=true; break; }
1943            else
1944              temp = horPositions[level[rightNodes[j]]];
1945          }
1946          //if(horPositions[level[descOrder[i]]]-1==
1947          //   horPositions[level[leftNodes[j]]])
1948          //    cantMove = true;
1949          if(cantMove)
1950            break;
1951         
1952          temp = horPositions[level[descOrder[i]]]+1;
1953          //****moving other vertices to left
1954          for(int j=0; j<rightNodes.length; j++) {
1955            if(temp==horPositions[level[rightNodes[j]]]) {
1956              //System.out.println("Moving "+
1957              //     (Node)m_nodes.elementAt(level[rightNodes[j]])).ID+" from "
1958              //     +horPositions[level[rightNodes[j]]]+" to "
1959              //     +(horPositions[level[rightNodes[j]]]+1) );
1960              horPositions[level[rightNodes[j]]] = 
1961                                    temp = horPositions[level[rightNodes[j]]]+1;
1962            }
1963          }
1964          //System.out.println("Moving main "+
1965          //    ((GraphNode)m_nodes.elementAt(level[descOrder[i]])).ID+" from "
1966          //    +horPositions[level[descOrder[i]]]+" to "
1967          //    +(horPositions[level[descOrder[i]]]+1));
1968          horPositions[level[descOrder[i]]]=horPositions[level[descOrder[i]]]+1;
1969        }
1970      }
1971  }
1972 
1973 
1974  /**
1975   * The following classes implement a double linked list to
1976   * be used in the crossings function.
1977   */
1978  private class MyList {
1979    int size;
1980    MyListNode first=null;
1981    MyListNode last=null;
1982   
1983    public void add(int i) {
1984      if(first==null)
1985        first = last = new MyListNode(i);
1986      else
1987        if(last.next==null) {
1988          last.next = new MyListNode(i);
1989          last.next.previous = last;
1990          last = last.next;
1991        }
1992        else {
1993          System.err.println("Error shouldn't be in here. Check MyList code"); 
1994          size--;
1995        }
1996      size++;
1997    }
1998   
1999    public void add(MyListNode n) {
2000      if(first==null)
2001        first = last = n;
2002      else
2003        if(last.next==null) {
2004          last.next = n;
2005          last.next.previous = last;
2006          last = last.next;
2007        }
2008        else {
2009          System.err.println("Error shouldn't be in here. Check MyList code"); 
2010          size--; 
2011        }
2012     
2013      size++;
2014    }
2015   
2016    public void remove(MyListNode n) {
2017      if(n.previous!=null)
2018        n.previous.next = n.next;
2019      if(n.next!=null)
2020        n.next.previous = n.previous;
2021      if(last==n)
2022        last = n.previous;
2023      if(first==n)
2024        first = n.next;
2025     
2026      size--;
2027    }
2028   
2029    public void remove(int i) {
2030      MyListNode temp=first;
2031      while(temp!=null && temp.n!=i) temp=temp.next;
2032     
2033      if(temp==null){ 
2034        System.err.println("element "+i+"not present in the list");
2035        return;
2036      }
2037     
2038      if(temp.previous!=null)
2039        temp.previous.next = temp.next;
2040      if(temp.next!=null)
2041        temp.next.previous = temp.previous;
2042      if(last==temp)
2043        last = temp.previous;
2044      if(first==temp)
2045        first = temp.next;
2046     
2047      size--;
2048    }
2049   
2050    public int size() {
2051      return size;
2052    }
2053   
2054  }
2055 
2056  private class MyListNode {
2057    int n;
2058    MyListNode next, previous;
2059   
2060    public MyListNode(int i) {
2061      n = i; next=null; previous=null;
2062    }
2063  }
2064 
2065} // HierarchicalBCEngine
Note: See TracBrowser for help on using the repository browser.