package bk; import java.util.ArrayList; import java.util.List; import javax.swing.JTree; import animation.CodeLine; import animation.ControlFlow; import animation.Memory; import animation.PseudoCodeNode; import animation.Memory.MemoryType; import animation.Memory.ReadOnlyMemory; import codelines.AbstractForLoop; import codelines.DeclareVariable; import codelines.ForEachLoop; import codelines.FunctionCall; import codelines.FunctionDefinition; import codelines.IfLoop; import codelines.SetVariable; import graph.LayeredGraphEdge; import graph.LayeredGraphNode; /** * The stage of the BK node placement algorithm where the blocks are computed. * @author kolja * */ public class BlockCalc { public static PseudoCodeNode calculateBlockGraph( JTree tree, PseudoCodeNode claclLayout ) { String[] vars = { "graph", "L", "r", "neighbors", "layout", "m", "i", "k", "mids", "n" }; @SuppressWarnings("serial") PseudoCodeNode root = new PseudoCodeNode( "function calculateBlockGraph( layout, graph )", vars, tree, new FunctionDefinition( new String[]{ "layout", "graph" } ) ) { @Override public String getDebugOutput( Memory m ) { if( m.isSomewhereDefined( "n", MemoryType.LOCAL ) ) m.read( "n", MemoryType.LOCAL).setSelected( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ); return super.getDebugOutput( m ); } }; root.add( new PseudoCodeNode( "L = graph.getContainedLayers();", vars, tree, new DeclareVariable>>( "L" ) { @Override protected ArrayList> value(ReadOnlyMemory m) { return m.read( "graph", MemoryType.LOCAL ).getContainedLayers(); } } ) ); PseudoCodeNode layerLoop = new PseudoCodeNode( "for i=layout.contains('DOWN') ? 0 : |L|-1 to layout.contains('DOWN') ? |L|-1 : 0 do", vars, tree, new AbstractForLoop( "i" ) { @Override protected Integer begin(ReadOnlyMemory m) { if( m.read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) ) return 0; return m.>>read( "L", MemoryType.LOCAL ).size() - 1; } @Override protected Integer step(ReadOnlyMemory m) { if( m.read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) ) return m.read( "i", MemoryType.LOCAL ) + 1; return m.read( "i", MemoryType.LOCAL ) - 1; } @Override protected boolean condition(ReadOnlyMemory m) { if( m.read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) ) return m.read( "i", MemoryType.LOCAL ) <= m.>>read( "L", MemoryType.LOCAL ).size() - 1; return m.read( "i", MemoryType.LOCAL ) >= 0; } }); root.add( layerLoop ); layerLoop.add( new PseudoCodeNode( "r = layout.contains('RIGHT') ? -1 : INFINITY;", vars, tree, new DeclareVariable( "r" ) { @Override protected Double value(ReadOnlyMemory m) { if( m.read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) ) return -1.0; return Double.POSITIVE_INFINITY; } } ) ); PseudoCodeNode nodeLoop = new PseudoCodeNode( "for k=layout.contains('RIGHT') ? 0 : |L[i]|-1 to layout.contains('RIGHT') ? |L[i]|-1 : 0 do", vars, tree, new AbstractForLoop( "k" ) { @Override protected Integer begin( ReadOnlyMemory m) { if( m.read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) ) return 0; return m.>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).size() - 1; } @Override protected Integer step( ReadOnlyMemory m) { if( m.read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) ) return m.read( "k", MemoryType.LOCAL ) + 1; return m.read( "k", MemoryType.LOCAL ) - 1; } @Override protected boolean condition( ReadOnlyMemory m) { if( m.read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) ) return m.read( "k", MemoryType.LOCAL ) <= m.>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).size() - 1; return m.read( "k", MemoryType.LOCAL ) >= 0; } }); nodeLoop.add( new PseudoCodeNode( "n = L[i][k];", vars, tree, new DeclareVariable( "n" ) { @Override protected LayeredGraphNode value(ReadOnlyMemory m) { return m.>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) ).get( m.read( "k", MemoryType.LOCAL ) ); } })); PseudoCodeNode ifNode = new PseudoCodeNode( "if n has subgraph then", vars, tree, new IfLoop() { @Override protected boolean condition(ReadOnlyMemory m) { return m.read( "n", MemoryType.LOCAL ).getContainedNodes().size() > 0; } } ); nodeLoop.add( ifNode ); ifNode.add( new PseudoCodeNode( "call calcLayout( layout, n );", vars, tree, new FunctionCall( claclLayout, new String[]{ "layout", "n" } ) ) ); nodeLoop.add( new PseudoCodeNode( "neighbors = layout.contains('DOWN') ? predecessors(n) : successors(n)", vars, tree, new DeclareVariable>( "neighbors" ) { @Override protected ArrayList value(ReadOnlyMemory m) { ArrayList list = m.read( "n", MemoryType.LOCAL ).getSortedOutgoingEdges(); if( m.read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) ) list = m.read( "n", MemoryType.LOCAL ).getSortedIncomingEdges(); ArrayList result = new ArrayList(); for( LayeredGraphEdge e : list ) { if( m.read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) ) result.add( e.getSources().get( 0 ) ); else result.add( e.getTargets().get( 0 ) ); } return result; } } ) ); layerLoop.add( nodeLoop ); nodeLoop.add( new PseudoCodeNode( "neighbors = layout.contains('RIGHT') ? neighbors : reverse( neighbors )", vars, tree, new SetVariable>( "neighbors" ) { @Override protected ArrayList value(ReadOnlyMemory m) { ArrayList list = m.read( "neighbors", MemoryType.LOCAL ); if( m.read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) ) return list; else { ArrayList result = new ArrayList(); for( int i = list.size() - 1; i >= 0; i-- ) result.add( list.get( i ) ); return result; } } } ) ); PseudoCodeNode ifNeighbors = new PseudoCodeNode( "if |neighbors| > 0 then", vars, tree, new IfLoop() { @Override protected boolean condition( ReadOnlyMemory m) { return m.>read( "neighbors", MemoryType.LOCAL ).size() > 0; } }); nodeLoop.add( ifNeighbors ); ifNeighbors.add( new PseudoCodeNode( "mids = [roundDown((|neighbors|-1)/2),roundUp((|neighbors|-1)/2)]", vars, tree, new DeclareVariable>( "mids" ) { @Override protected ArrayList value(ReadOnlyMemory m) { int size = m.>read( "neighbors", MemoryType.LOCAL ).size() - 1; int m1 = size / 2, m2 = (int)(size / 2.0 + 0.5); ArrayList list = new ArrayList(); list.add( m1 ); if( m1 != m2 ) list.add( m2 ); return list; } } ) ); PseudoCodeNode midLoop = new PseudoCodeNode( "foreach m in mids do", vars, tree, new ForEachLoop( "m" ) { @Override protected List list(ReadOnlyMemory m) { return m.read( "mids", MemoryType.LOCAL ); } } ); ifNeighbors.add( midLoop ); PseudoCodeNode ifAlign = new PseudoCodeNode( "if align[n] == n then", vars, tree, new IfLoop() { @Override protected boolean condition(ReadOnlyMemory m) { LayeredGraphNode n = m.read( "n", MemoryType.LOCAL ); return n.getAlign( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ) == n; } }); midLoop.add( ifAlign ); PseudoCodeNode ifMarked = new PseudoCodeNode( "if (neighbors[m],n) not conflicted and ((r < pos(neighbors[m]) and layout.contains('RIGHT')) or (r > pos(neighbors[m]) and layout.contains('LEFT'))) then", vars, tree, new IfLoop() { @Override protected boolean condition(ReadOnlyMemory m) { LayeredGraphEdge e = m.read( "graph", MemoryType.LOCAL ).findEdgeBetween( m.>read( "neighbors", MemoryType.LOCAL ).get( m.read( "m", MemoryType.LOCAL ) ), m.read( "n", MemoryType.LOCAL ) ); if( e == null ) e = m.read( "graph", MemoryType.LOCAL ).findEdgeBetween( m.read( "n", MemoryType.LOCAL ), m.>read( "neighbors", MemoryType.LOCAL ).get( m.read( "m", MemoryType.LOCAL ) ) ); ArrayList layerBefore; if( m.read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) ) layerBefore = m.>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) - 1 ); else layerBefore = m.>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) + 1 ); int posU = layerBefore.indexOf( m.>read( "neighbors", MemoryType.LOCAL ).get( m.read( "m", MemoryType.LOCAL ) ) ); return !e.isConflicted( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ) && ( ( m.read( "r", MemoryType.LOCAL ) < posU && m.read( "layout", MemoryType.LOCAL ).contains( "RIGHT" ) ) || ( m.read( "r", MemoryType.LOCAL ) > posU && m.read( "layout", MemoryType.LOCAL ).contains( "LEFT" ) ) ); } }); ifAlign.add( ifMarked ); ifMarked.add( new PseudoCodeNode( "align[neighbors[m]] = n;", vars, tree, new CodeLine() { @Override public ControlFlow runForward(Memory m) { LayeredGraphNode u = m.>read( "neighbors", MemoryType.LOCAL ).get( m.read( "m", MemoryType.LOCAL ) ); LayeredGraphNode v = m.read( "n", MemoryType.LOCAL ); LayeredGraphNode old = u.getAlign( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ); u.setAlign( v, LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ); actions.push( (Memory mem) -> { u.setAlign( old, LayoutType.fromString( mem.read( "layout", MemoryType.LOCAL ) ) ); }); return new ControlFlow( ControlFlow.STEP_OVER ); } }) ); ifMarked.add( new PseudoCodeNode( "root[n] = root[neighbors[m]];", vars, tree, new CodeLine() { @Override public ControlFlow runForward(Memory m) { LayeredGraphNode u = m.>read( "neighbors", MemoryType.LOCAL ).get( m.read( "m", MemoryType.LOCAL ) ); LayeredGraphNode v = m.read( "n", MemoryType.LOCAL ); LayeredGraphNode old = v.getRoot( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ); v.setRoot( u.getRoot( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ), LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ); actions.push( (Memory mem) -> { v.setRoot( old, LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ); }); return new ControlFlow( ControlFlow.STEP_OVER ); } }) ); ifMarked.add( new PseudoCodeNode( "align[n] = root[n];", vars, tree, new CodeLine() { @Override public ControlFlow runForward(Memory m) { LayeredGraphNode v = m.read( "n", MemoryType.LOCAL ); LayeredGraphNode old = v.getAlign( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ); v.setAlign( v.getRoot( LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ), LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ); actions.push( (Memory mem) -> { v.setAlign( old, LayoutType.fromString( m.read( "layout", MemoryType.LOCAL ) ) ); }); return new ControlFlow( ControlFlow.STEP_OVER ); } }) ); ifMarked.add( new PseudoCodeNode( "r = pos(neighbors[m]);", vars, tree, new SetVariable( "r" ) { @Override protected Double value(ReadOnlyMemory m) { ArrayList layerBefore; if( m.read( "layout", MemoryType.LOCAL ).contains( "DOWN" ) ) layerBefore = m.>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) - 1 ); else layerBefore = m.>>read( "L", MemoryType.LOCAL ).get( m.read( "i", MemoryType.LOCAL ) + 1 ); LayeredGraphNode u = m.>read( "neighbors", MemoryType.LOCAL ).get( m.read( "m", MemoryType.LOCAL ) ); return (double)layerBefore.indexOf( u ); } }) ); return root; } }