class Graph {

    public Graph permute(int[] p) {

        if (p.length != order)
            throw new IllegalArgumentException("permuation size should equal |V| (order)");

        Graph cpy = new Graph(order);
        cpy.flags = flags;
        cpy.order = order;
        cpy.size = size;

        for (int u = 0; u < order; u++) {
            int d = degrees[u];
            // v is the image of u in the permutation
            final int v = p[u];
            if (d > 4) cpy.edges[v] = new Edge[d];
            cpy.atoms[v]    = atoms[u];
            cpy.valences[v] = valences[u];
            cpy.addTopology(topologyOf(u).transform(p));
            while (--d >= 0) {
                final Edge e = edgeAt(u, d);

                // important this is the second time we have seen the edge
                // so the capacity must have been allocated. otherwise we
                // would get an index out of bounds
                if (u > e.other(u)) {
                    // w is the image of vertex adjacen to u
                    final int  w = p[e.other(u)];
                    final Edge f = new Edge(v, w, e.bond(u));
                    cpy.edges[v][cpy.degrees[v]++] = f;
                    cpy.edges[w][cpy.degrees[w]++] = f;
                    cpy.size++;
                }
            }
        }

        // ensure edges are in sorted order
        return cpy.sort(new CanOrderFirst());
    }

      Graph(int expSize);
      Graph(Graph org);

}