java.lang.IllegalArgumentException:树必须不包含child

时间:2014-06-20 13:21:28

标签: java algorithm jung jung2

我创建了以下jung2可视化。我的代码将文本可视化为树。基本上我一次使用两个输入:

        /*
         * INPUT 1
         */
        String text = "=IF(A2=1;0;IF(D2=D3;IF(C2=1;TRUE;FALSE);4))";

        /*
         * INPUT 2
         */
        String text = "=IF(A2=1;0;IF(D2=D3;IF(C2=1;TRUE;FALSE);TRUE))";

我的问题是,第一个输入按预期工作,但在使用Input 2时,在最后一个元素4而不是TRUE中只是不同,我得到错误:

Exception in thread "main" java.lang.IllegalArgumentException: Tree must not already contain child D2=D3
    at edu.uci.ics.jung.graph.DelegateTree.addChild(DelegateTree.java:182)
    at edu.uci.ics.jung.graph.DelegateTree.addEdge(DelegateTree.java:102)
    at edu.uci.ics.jung.graph.DelegateTree.addEdge(DelegateTree.java:346)
    at edu.uci.ics.jung.graph.util.TreeUtils.growSubTree(TreeUtils.java:76)
    at edu.uci.ics.jung.graph.util.TreeUtils.growSubTree(TreeUtils.java:80)
    at edu.uci.ics.jung.graph.DelegateForest.getTrees(DelegateForest.java:295)
    at edu.uci.ics.jung.graph.util.TreeUtils.getRoots(TreeUtils.java:34)
    at edu.uci.ics.jung.algorithms.layout.TreeLayout.buildTree(TreeLayout.java:102)
    at edu.uci.ics.jung.algorithms.layout.TreeLayout.<init>(TreeLayout.java:97)
    at edu.uci.ics.jung.algorithms.layout.TreeLayout.<init>(TreeLayout.java:75)
    at justDelete.me.codeTestingPackage.Test.<init>(Test.java:131)
    at justDelete.me.codeTestingPackage.Test.main(Test.java:396)

令人困惑的是,字符串被正确解析并且可以被程序正确使用,如:

[IF, A2=1, 0, IF, D2=D3, IF, C2=1, TRUE, FALSE, TRUE]

这是我的程序版本,可以在评论中使用input 2(&#34;破坏&#34;输入)运行:

@SuppressWarnings("serial")
public class Test extends JApplet {

    /**
     * the graph
     */
    Forest<String,Integer> graph;


    private static final Logger log = Logger.getLogger(Test.class);


    Factory<DirectedGraph<String,Integer>> graphFactory = 
            new Factory<DirectedGraph<String,Integer>>() {

        public DirectedGraph<String, Integer> create() {
            return new DirectedSparseMultigraph<String,Integer>();
        }
    };

    Factory<Tree<String,Integer>> treeFactory =
            new Factory<Tree<String,Integer>> () {

        public Tree<String, Integer> create() {
            return new DelegateTree<String,Integer>(graphFactory);
        }
    };



    Factory<Integer> edgeFactory = new Factory<Integer>() {
        int i=0;
        public Integer create() {
            return i++;
        }};

        Factory<String> vertexFactory = new Factory<String>() {
            int i=0;
            public String create() {
                return "V"+i++;
            }};

            /**
             * the visual component and renderer for the graph
             */
            VisualizationViewer<String,Integer> vv;

            VisualizationServer.Paintable rings;

            String root;

            TreeLayout<String,Integer> layout;
            @SuppressWarnings("unchecked")
            FRLayout layout1;

            TreeCollapser collapser;

            RadialTreeLayout<String,Integer> radialLayout;

            @SuppressWarnings("unchecked")
            public Test() {

                // create a simple graph for the demo
                graph = new DelegateForest<String,Integer>();

                createTree();

                layout = new TreeLayout<String,Integer>(graph);
                collapser = new TreeCollapser();

                radialLayout = new RadialTreeLayout<String,Integer>(graph);
                radialLayout.setSize(new Dimension(600,600));
                vv =  new VisualizationViewer<String,Integer>(layout, new Dimension(600,600));
                vv.setBackground(Color.white);
                vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line());
                vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
                vv.getRenderContext().setVertexShapeTransformer(new ClusterVertexShapeFunction());
                // add a listener for ToolTips
                vv.setVertexToolTipTransformer(new ToStringLabeller());
                vv.getRenderContext().setArrowFillPaintTransformer(new ConstantTransformer(Color.lightGray));
                rings = new Rings();

                Container content = getContentPane();
                final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
                content.add(panel);

                final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();

                vv.setGraphMouse(graphMouse);

                JComboBox modeBox = graphMouse.getModeComboBox();
                modeBox.addItemListener(graphMouse.getModeListener());
                graphMouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);

                final ScalingControl scaler = new CrossoverScalingControl();

                JButton plus = new JButton("+");
                plus.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        scaler.scale(vv, 1.1f, vv.getCenter());
                    }
                });
                JButton minus = new JButton("-");
                minus.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        scaler.scale(vv, 1/1.1f, vv.getCenter());
                    }
                });

                JToggleButton radial = new JToggleButton("Radial");
                radial.addItemListener(new ItemListener() {

                    public void itemStateChanged(ItemEvent e) {
                        if(e.getStateChange() == ItemEvent.SELECTED) {
                            //                  layout.setRadial(true);
                            vv.setGraphLayout(radialLayout);
                            vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
                            vv.addPreRenderPaintable(rings);
                        } else {
                            //                  layout.setRadial(false);
                            vv.setGraphLayout(layout);
                            vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
                            vv.removePreRenderPaintable(rings);
                        }
                        vv.repaint();
                    }});

                JButton collapse = new JButton("Collapse");
                collapse.addActionListener(new ActionListener() {

                    public void actionPerformed(ActionEvent e) {
                        Collection picked =new HashSet(vv.getPickedVertexState().getPicked());
                        if(picked.size() == 1) {
                            Object root = picked.iterator().next();
                            Forest inGraph = (Forest)layout.getGraph();

                            try {
                                collapser.collapse(vv.getGraphLayout(), inGraph, root);
                            } catch (InstantiationException e1) {
                                // TODO Auto-generated catch block
                                e1.printStackTrace();
                            } catch (IllegalAccessException e1) {
                                // TODO Auto-generated catch block
                                e1.printStackTrace();
                            }

                            vv.getPickedVertexState().clear();
                            vv.repaint();
                        }
                    }});

                JButton expand = new JButton("Expand");
                expand.addActionListener(new ActionListener() {

                    public void actionPerformed(ActionEvent e) {
                        Collection picked = vv.getPickedVertexState().getPicked();
                        for(Object v : picked) {
                            if(v instanceof Forest) {
                                Forest inGraph = (Forest)layout.getGraph();
                                collapser.expand(inGraph, (Forest)v);
                            }
                            vv.getPickedVertexState().clear();
                            vv.repaint();
                        }
                    }});

                JPanel scaleGrid = new JPanel(new GridLayout(1,0));
                scaleGrid.setBorder(BorderFactory.createTitledBorder("Zoom"));

                JPanel controls = new JPanel();
                scaleGrid.add(plus);
                scaleGrid.add(minus);
                controls.add(radial);
                controls.add(scaleGrid);
                controls.add(modeBox);
                controls.add(collapse);
                controls.add(expand);
                content.add(controls, BorderLayout.SOUTH);
            }

            class Rings implements VisualizationServer.Paintable {

                Collection<Double> depths;

                public Rings() {
                    depths = getDepths();
                }

                private Collection<Double> getDepths() {
                    Set<Double> depths = new HashSet<Double>();
                    Map<String,PolarPoint> polarLocations = radialLayout.getPolarLocations();
                    for(String v : graph.getVertices()) {
                        PolarPoint pp = polarLocations.get(v);
                        depths.add(pp.getRadius());
                    }
                    return depths;
                }

                public void paint(Graphics g) {
                    g.setColor(Color.lightGray);

                    Graphics2D g2d = (Graphics2D)g;
                    Point2D center = radialLayout.getCenter();

                    Ellipse2D ellipse = new Ellipse2D.Double();
                    for(double d : depths) {
                        ellipse.setFrameFromDiagonal(center.getX()-d, center.getY()-d, 
                                center.getX()+d, center.getY()+d);
                        Shape shape = vv.getRenderContext().
                                getMultiLayerTransformer().getTransformer(Layer.LAYOUT).transform(ellipse);
                        g2d.draw(shape);
                    }
                }

                public boolean useTransform() {
                    return true;
                }
            }

            /**
             * create Tree
             */
            private void createTree() {

                /*
                 * INPUT 1
                 */
//              String text = "=IF(A2=1;0;IF(D2=D3;IF(C2=1;TRUE;FALSE);4))";

                /*
                 * INPUT 2
                 */
                String text = "=IF(A2=1;0;IF(D2=D3;IF(C2=1;TRUE;FALSE);TRUE))";


                text.toUpperCase();

                //START
                String[] operands = text.substring(1, text.length()).split("[;()]+");

                System.out.println(Arrays.toString(operands));
                int numIfs = operands.length / 3; // actually (operands.length - 1) / 3 but int division makes it the same 
                String[] nodes = new String[numIfs]; // stores the nodes (test strings)
                int[] operandNos = new int[numIfs]; // stores the number of operands the if currently has
                int nodesIndex = -1; // the index of the if node currently parsed
                for (String s : operands) {
                    if (s.equals("IF")) {
                        // new if found -> increase position in the "stack" (nodes)
                        operandNos[++nodesIndex] = 0;
                    } else {
                        //                      addVertex(s);
                        graph.addVertex(s);
                        switch (operandNos[nodesIndex]++) {
                        case 0:
                            // first operand = node name
                            nodes[nodesIndex] = s;
                            break;
                        case 1:
                            // second operand found -> add edge
                            graph.addEdge(edgeFactory.create(), s, nodes[nodesIndex]);
                            break;
                        case 2:
                            // last operand found -> add edge and go back
                            do {
                                graph.addEdge(edgeFactory.create(), s, nodes[nodesIndex]);
                                s = nodes[nodesIndex--];
                            } while (nodesIndex >= 0 && operandNos[nodesIndex]++ == 2);
                            if (nodesIndex >= 0) {
                                // was not the last operand of the IF
                                graph.addEdge(edgeFactory.create(), s, nodes[nodesIndex]);
                            }
                        }
                    }
                }       
                //END

            }

            class ClusterVertexShapeFunction<V> extends EllipseVertexShapeTransformer<V>
            {

                ClusterVertexShapeFunction() {
                    setSizeTransformer(new ClusterVertexSizeFunction<V>(20));
                }
                @SuppressWarnings("unchecked")
                @Override
                public Shape transform(V v) {
                    if(v instanceof Graph) {
                        int size = ((Graph)v).getVertexCount();
                        if (size < 8) {   
                            int sides = Math.max(size, 3);
                            return factory.getRegularPolygon(v, sides);
                        }
                        else {
                            return factory.getRegularStar(v, size);
                        }
                    }
                    return super.transform(v);
                }
            }

            /**
             * A demo class that will make vertices larger if they represent
             * a collapsed collection of original vertices
             * @author Tom Nelson
             *
             * @param <V>
             */
            class ClusterVertexSizeFunction<V> implements Transformer<V,Integer> {
                int size;
                public ClusterVertexSizeFunction(Integer size) {
                    this.size = size;
                }

                public Integer transform(V v) {
                    if(v instanceof Graph) {
                        return 30;
                    }
                    return size;
                }
            }



            /**
             * a driver for this demo
             */
            public static void main(String[] args) {
                JFrame frame = new JFrame();
                Container content = frame.getContentPane();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                content.add(new Test());
                frame.pack();
                frame.setVisible(true);
            }
}

使用输入2执行代码时,我收到发布的错误。任何建议为什么会这样?我的猜测是字符串是相同的,即使这有点荒谬,因为树的叶子应该是唯一的。那么,如何处理这个问题?

感谢您的回答!

1 个答案:

答案 0 :(得分:2)

问题是同一个顶点应该出现多次。

人们可以在解释细节方面走得很远,但只是提出这个想法:想象一下,JUNG中的Graph在内部被维护为一堆Map。例如,Map<V, Set<E>>将每个顶点映射到从该顶点开始的边集。现在,您将顶点的类型定义为String。当有多个顶点应该由相同的String标识时,那么特定的图形(应该是)可能会变得不一致。

更具启发性:您想要创建一个如下所示的树:

tree.getNode("A").addChild("TRUE");
tree.getNode("B").addChild("TRUE");

这意味着对应于字符串"TRUE"的节点将具有两个父节点,即节点"A"和节点"B"。 (你的案例中的实际情况不同,但我没有详细分析解析 - 无论如何,消息&#34;树必须不包含子D2 = D3&#34; 表示这是&#34;这种问题&#34;。

对此的解决方案相当简单,虽然可能有点不方便:您必须确保可能有多个具有相同String的顶点,这些顶点仍然被认为是不同的顶点。特别是:当对象实际上应该是不同的顶点时,这些顶点的equals方法必须返回false

这可以通过引入一个简单的Vertex类来实现。我在这里草拟了它,它似乎有效,但是又一次:我做了分析这个解析器在那里做了什么,你应该仔细检查是否还有假定顶点的地方{ {1}}现在应该更改为使用String对象(顺便说一句,代码可能需要清理)。但是,它应该显示解决这个问题的基本方法:

Vertex