#!/usr/bin/perl -w

# Copyright 2015 Kevin Ryde
#
# This file is part of Graph-Graph6.
#
# Graph-Graph6 is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 3, or (at your option) any later
# version.
#
# Graph-Graph6 is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with Graph-Graph6.  If not, see <http://www.gnu.org/licenses/>.

use strict;
use 5.010;
use FindBin;
use File::Slurp;
use List::Util 'max';
use Graph;
use Graph::Writer::Graph6;
use Graph::Easy;
use Graph::Easy::As_graph6;
use Graph::Easy::Parser::Graph6;
use Graph::Graph6;
use IPC::Run;
use List::Util 'min','max';
use MyGraphs;

# uncomment this to run the ### lines
# use Smart::Comments;







{
  # Thomassen 24 non-planar cubic hypohamiltonian
  # Carsten Thomassen, "Planar Cubic Hypohamiltonian and Hypotraceable Graphs",
  # Journal of Combinatorial Theory, Series B, volume 30, 1981, pages 36-44.
  #
  # https://hog.grinvin.org/ViewGraphInfo.action?id=21146
  #
  #       -----------------s1--------------------
  #      /                  |                    \
  #     /              /---s2------\              \
  #   a1---a2---a3---a4             b1---b2---b3---b4
  #    |    |    |    |              |    |    |    |
  #   a10-           -a5            b10-           -b5
  #    |    |    |    |              |    |    |    |
  #   a9---a8---a7---a6             b9---b8---b7---b6
  #     \              \-----      /              /
  #      \                     \                 /
  #       --------------t1------t2---------------

  my $graph = Graph->new (undirected => 1);
  $graph->add_cycle('a1','a2','a3','a4','a5','a6','a7','a8','a9','a10');
  $graph->add_edge('a2','a8');
  $graph->add_edge('a3','a7');
  $graph->add_edge('a5','a10');

  $graph->add_cycle('b1','b2','b3','b4','b5','b6','b7','b8','b9','b10');
  $graph->add_edge('b2','b8');
  $graph->add_edge('b3','b7');
  $graph->add_edge('b5','b10');
  
  $graph->add_path('s1','s2');
  $graph->add_path('a1','s1','b4');
  $graph->add_path('a4','s2','b1');
  
  $graph->add_path('t1','t2');
  $graph->add_path('a9','t1','b9');
  $graph->add_path('a6','t2','b6');

  foreach my $v ($graph->vertices) {
    my $degree = $graph->vertex_degree($v);
    if ($degree != 3) {
      print "$v degree $degree\n";
    }
  }
  {
    my %seen;
    foreach my $edge ($graph->edges) {
      my ($u,$v) = sort @$edge;
      if ($seen{"$u,$v"}++) {
        print "duplicate $u -- $v\n";
      }
    }
  }

  my $num_vertices = $graph->vertices;
  my $num_edges = $graph->edges;
  print "$num_vertices vertices, $num_edges edges\n";
  #  Graph_view($graph);
  hog_searches_html($graph);

  # $graph = Graph->new (undirected => 1);
  # $graph->add_cycle('a','b','c');
  # $graph->add_path('a','d','c');
  # $graph->add_path('a','e','c');

  foreach my $v ($graph->vertices) {
    my $g = $graph->copy;
    $g->delete_vertex($v);
    my $h = Graph_is_hamiltonian($g);
    print "  sans $v hamiltonian $h\n";
  }
  my $h = Graph_is_hamiltonian($graph);
  print "hamiltonian $h\n";
  exit 0;

  sub Graph_is_hamiltonian {
    my ($graph) = @_;
    my @vertices = $graph->vertices;
    my $num_vertices = scalar(@vertices);
    my %neighbours;
    foreach my $v (@vertices) {
      $neighbours{$v} = [ $graph->neighbours($v) ];
    }

    my @path = ($vertices[0]);
    my %visited = ($path[0] => 1);
    my @nn = (-1);
    my $upto = 0;
    for (;;) {
      ### at: join('--',@path)
      my $v = $path[$upto];
      my $n = $nn[$upto]++;
      my $to = $neighbours{$v}->[$n];
      ### $to
      if (! defined $to) {
        ### no more neighbours, backtrack ...
        $visited{$v} = 0;
        $upto--;
        if ($upto < 0) { return 0; }
        next;
      }
      if ($visited{$to}) {
        ### to is visited ...
        if ($upto == $num_vertices-1 && $to eq $path[0]) {
          ### found cycle ...
          return 1;
        }
        next;
      }

      # extend path to $to
      $upto++;
      $path[$upto] = $to;
      $visited{$to} = 1;
      $nn[$upto] = -1;
    }
  }
}

{
  # Thomassen 94 planar cubic hypohamiltonian
  # https://hog.grinvin.org/ViewGraphInfo.action?id=1359
  # my(k=23,n=4*k+2); [k,n, 1/4*(n-90)^2+137, 1/2*n-44]
  # Carsten Thomassen, "Planar Cubic Hypohamiltonian and Hypotraceable Graphs",
  # Journal of Combinatorial Theory, Series B, volume 30, 1981, pages 36-44.

  my $graph = Graph->new (undirected => 1);
  $graph->add_cycle('a1','a2','a3','a4');
  $graph->add_edge('a1','b1');
  $graph->add_edge('a2','b2');
  $graph->add_edge('a3','b3');
  $graph->add_edge('a4','b4');

  $graph->add_cycle('b1','c1','e1','c2',
                    'b2','d2','f2','d3',
                    'b3','c3','e2','c4',
                    'b4','d4','f1','d1');
  $graph->add_edge('c1','g1'); $graph->add_edge('d1','h1');
  $graph->add_edge('c2','g2'); $graph->add_edge('d2','h2');
  $graph->add_edge('c3','g3'); $graph->add_edge('d3','h3');
  $graph->add_edge('c4','g4'); $graph->add_edge('d4','h4');
  $graph->add_edge('e1','i1');
  $graph->add_edge('e2','i2');
  $graph->add_edge('f1','j1');
  $graph->add_edge('f2','j2');

  $graph->add_cycle('h1','g1','k1','i1','k2','g2',
                    'h2','m2','r2','s2','y2',
                    'j2','y3','s3','r3','m3',
                    'h3','g3','k3','i2','k4','g4',
                    'h4','m4','r4','s4','y4',
                    'j1','y1','s1','r1','m1');

  $graph->add_path('k1','l1','n1', 'o1', 'n2','l2','k2');
  $graph->add_path('k3','l3','n3', 'o2', 'n4','l4','k4');
  $graph->add_edge('m1','l1');
  $graph->add_edge('m2','l2');
  $graph->add_edge('m3','l3');
  $graph->add_edge('m4','l4');

  $graph->add_cycle('p1','t2','u2','v2','w1','v1','u1','t1');
  $graph->add_cycle('p2','t4','u4','v4','w2','v3','u3','t3');

  $graph->add_edge('q1','n1');  $graph->add_edge('q1','r1');
  $graph->add_edge('q2','n2');  $graph->add_edge('q2','r2');
  $graph->add_edge('q3','n3');  $graph->add_edge('q3','r3');
  $graph->add_edge('q4','n4');  $graph->add_edge('q4','r4');
  $graph->add_edge('q1','t1');
  $graph->add_edge('q2','t2');
  $graph->add_edge('q3','t3');
  $graph->add_edge('q4','t4');

  $graph->add_edge('o1','p1');  $graph->add_edge('w1','odot1');
  $graph->add_edge('o2','p2');  $graph->add_edge('w2','odot2');

  $graph->add_cycle('p1','t2','u2','v2','w1','v1','u1','t1');
  $graph->add_cycle('p2','t3','u3','v3','w2','v4','u4','t4');

  $graph->add_edge('u1','s1'); $graph->add_edge('v1','x1');
  $graph->add_edge('u2','s2'); $graph->add_edge('v2','x2');
  $graph->add_edge('u3','s3'); $graph->add_edge('v3','x3');
  $graph->add_edge('u4','s4'); $graph->add_edge('v4','x4');

  $graph->add_edge('odot1','w1'); $graph->add_edge('odot2','w2');
  $graph->add_edge('odot1','z1'); $graph->add_edge('odot2','z3');
  $graph->add_edge('odot1','z2'); $graph->add_edge('odot2','z4');

  $graph->add_edge('adot1','adot2');

  $graph->add_path('y1','x1','z1','adot1','z4','x4','y4');
  $graph->add_path('y2','x2','z2','adot2','z3','x3','y3');

  foreach my $v ($graph->vertices) {
    my $degree = $graph->vertex_degree($v);
    if ($degree != 3) {
      print "$v degree $degree\n";
    }
  }
  {
    my %seen;
    foreach my $edge ($graph->edges) {
      my ($u,$v) = sort @$edge;
      if ($seen{"$u,$v"}++) {
        print "duplicate $u -- $v\n";
      }
    }
  }

  my $num_vertices = $graph->vertices;
  my $num_edges = $graph->edges;
  print "$num_vertices vertices, $num_edges edges\n";
  #  Graph_view($graph);
  hog_searches_html($graph);

  foreach my $v ($graph->vertices) {
    my $g = $graph->copy;
    $g->delete_vertex($v);
    my $h = Graph_is_hamiltonian($g);
    print "  sans $v hamiltonian $h\n";
  }
  my $h = Graph_is_hamiltonian($graph);
  print "hamiltonian $h\n";
  exit 0;
}

{
  my $graph = Graph->new (undirected => 1);
  $graph->add_vertex(0);
  $graph->add_vertex(2);
  my $l = $graph->path_length(0,0);
  ### $l
  my $d = $graph->diameter;
  ### $d
  my $dd = $graph->diameter // 0;
  ### $dd
  exit 0;
}

{
  # Knor, Macaj, Potocnik, Skrekovski  W(L^3(G)) = W(G)
  # a = 128 + 3*i^2 + 3*j^2 - 3*i*j + i
  # b = 128 + 3*i^2 + 3*j^2 - 3*i*j + j
  # c = 128 + 3*i^2 + 3*j^2 - 3*i*j + i+j
  # a+b+c == 9*i^2 + 9*j^2 - 9*i*j + 2*i + 2*j + 384
  # abc(i,j) = 9*i^2 + 9*j^2 - 9*i*j + 2*i + 2*j + 384;
  # my(m=10^10); for(i=0,20,for(j=0,20, m=min(m,abc(i,j)))); m
  # minimum 384 of branches plus 4 in middle = 388 vertices
  exit 0;
}

{
  # Dobrynin, Entringer, Gutman  Wiener index W(L^2(G)) = W(G)
  # A051175 number of such trees
  #
  # n=9 hog not
  # n=10 hog not
  # n=11 hog not

  my $iterator_func = make_tree_iterator_edge_aref
    (num_vertices_min => 2,
     num_vertices_max => 11);
  my @array;
 TREE: while (my $edge_aref = $iterator_func->()) {
    my $graph = Graph_from_edge_aref($edge_aref);
    my $W = Graph_Wiener_index($graph);
    my $graph_L = Graph_line_graph($graph);
    my $graph_L2 = Graph_line_graph($graph_L);
    my $WL2 = Graph_Wiener_index($graph_L2);
    if ($W == $WL2) {
      my $num_vertices = $graph->vertices;
      print "[$num_vertices] $graph\n";
      $graph->set_graph_attribute (name => "W(G)=W(L^2(G)) $num_vertices vertices");
      $graph_L->set_graph_attribute (name => "line graph");
      $graph_L2->set_graph_attribute (name => "line graph * 2");
      # Graph_view($graph);
      push @array, $graph;
      push @array, $graph_L;
      push @array, $graph_L2;
    }
  }
  hog_searches_html(@array);
  exit 0;
}
{
  # Szeged index
  # same as Wiener index on trees, bigger when cycles

  unshift @INC, "$FindBin::Bin/../../dragon/tools";
  my @values;
  foreach my $k (2 .. 7) {
    # require Graph::Maker::Star;
    # my $graph = Graph::Maker->new('star', N=>$k, undirected=>1);

    # require Graph::Maker::Linear;
    # my $graph = Graph::Maker->new('linear', N=>$k, undirected=>1);

    # require Graph::Maker::BalancedTree;
    # my $graph = Graph::Maker->new('balanced_tree',
    #                               fan_out => 2, height => $k,
    #                               undirected=>1,
    #                              );

    # require Graph::Maker::FibonacciTree;
    # my $graph = Graph::Maker->new('fibonacci_tree',
    #                               height => $k,
    #                               # leaf_reduced => 1,
    #                               # series_reduced => 1,
    #                               undirected=>1,
    #                              );

    # require Graph::Maker::BinomialTree;
    # my $graph = Graph::Maker->new('binomial_tree',
    #                               order => $k,
    #                               undirected => 1,
    #                              );

    # require Graph::Maker::TwindragonAreaTree;
    # my $graph = Graph::Maker->new('twindragon_area_tree',
    #                               level => $k,
    #                               undirected => 1,
    #                              );

    require Graph::Maker::PlanePath;
    my $graph = Graph::Maker->new('planepath', level=>$k,
                                  planepath=>'TerdragonCurve',
                                  undirected => 1);

    # if ($graph->vertices < 20) {
    #   print $graph;
    #   Graph_view($graph);
    # }
    my $Sz = Graph_Szeged_index($graph);
    my $W = Graph_Wiener_index($graph);
    print "k=$k  Sz=$Sz W=$W\n";
    push @values, $Sz;
  }
  require Math::OEIS::Grep;
  Math::OEIS::Grep->search(array => \@values, verbose=>1);
  exit 0;
}
sub Graph_Szeged_index {
  my ($graph) = @_;
  my @vertices = $graph->vertices;
  my $total;
  foreach my $edge ($graph->edges) {
    my ($u,$v) = @$edge;
    my $nu = 0;
    my $nv = 0;
    foreach my $w (@vertices) {
      my $ulen = $graph->path_length($u,$w) // die "no path $u to $w";
      my $vlen = $graph->path_length($v,$w) // die "no path $v to $w";
      if ($ulen < $vlen) { $nu++; }
      elsif ($vlen < $ulen) { $nv++; }
    }
    $total += $nu * $nv;
  }
  return $total;
}

{
  # degree >=2 counts, drawing
  # 1,3,11,62,510,7459
  # cf A069725 up to 62

  my $num_vertices = 5;

  require IPC::Run;
  my @args = ('-d2', # degree >=2
              $num_vertices);
  my $h = IPC::Run::start(['nauty-geng',@args], '>pipe', \*GENG);
  require Graph::Reader::Graph6;
  my $fh = \*GENG;
  my @array;

  require Graph::Maker::Complete;
  my $complete = Graph::Maker->new('complete', N=>$num_vertices);

  # my $parser = Graph::Easy::Parser::Graph6->new;
  # while (my $easy = $parser->from_file($fh)) {
  #   $easy->set_attribute('x-dot-overlap',"false");
  #   $easy->set_attribute('x-dot-splines',"true");
  #   # Graph_Easy_view($easy);
  #   push @array, $easy;
  # }

  my $reader = Graph::Reader::Graph6->new;
  my $count = 0;
 GRAPH: while (my $graph = $reader->read_graph($fh)) {
    {
      my $odd = 0;
      foreach my $v ($graph->vertices) {
        if ($graph->degree($v) % 2) {
          $odd++;
          next GRAPH if $odd > 2;
        }
      }
    }
    $count++;
    # Graph_view($graph);
    # push @array, $graph;
    # if (Graph_is_isomorphic($graph, $complete)) {
    #   $graph->set_graph_attribute (name => "complete $num_vertices");
    # }
  }
  print "count $count\n";
  hog_searches_html(@array);
  exit 0;
}


{
  # hog trees and paths

  # Rpred high to low -- not
  # Lpred high to low, and reverse -- not
  # Rpred+Lpred for bridges -- not
  # complex plus boundary state machine and reversed -- not
  # C right boundary and reverse -- not
  # C doubles and reverse -- not
  # Terdragon Eboth -- not

  require Graph::Easy::As_sparse6;
  require Graph::Easy::As_graph6;
  require Graph::Writer::Graph6;
  unshift @INC, "$FindBin::Bin/../../dragon/tools";
  my @graphs;
  for (my $k = 0; @graphs < 11; $k++) {
    my $graph;

    # {
    #   # twindragon k=1..4 not
    #   #  k=1 two squares F?df_ not
    #   require Graph::Maker::Twindragon;
    #   $graph = Graph::Maker->new('twindragon', level=>$k, arms=>1,
    #                              undirected=>1);
    # }
    # {
    #   # Terdragon 3-cycle k=1..2 not
    #   # neighbours6 shortcuts on boundary level=2,3 not
    #   #  level=1 https://hog.grinvin.org/ViewGraphInfo.action?id=28
    #   require Graph::Maker::PlanePath;
    #   $graph = Graph::Maker->new('planepath', level=>$k,
    #                              planepath=>'TerdragonCurve',
    #                              n_lo => 2 * 3**$k,
    #                              n_hi => 5 * 3**$k,
    #                             );
    # }
    # {
    #   # R5 quad-r5dragon 4-cycle k=1 not
    #   require Graph::Maker::R5Twindragon;
    #   $graph = Graph::Maker->new('r5twindragon', level=>$k, arms=>1,
    #                              undirected=>1);
    # }
    # {
    #   # twindragon area tree
    #   #  k=3 https://hog.grinvin.org/ViewGraphInfo.action?id=700
    #   #  k=4..5 not
    #   require Graph::Maker::TwindragonAreaTree;
    #   $graph = Graph::Maker->new('twindragon_area_tree', level=>$k,
    #                              undirected=>1);
    # }
    # {
    #   # Dragon blob k=5..6 not
    #   # k=4 single square https://hog.grinvin.org/ViewGraphInfo.action?id=674
    #   #
    # require Graph::Maker::Dragon;
    #   $graph = Graph::Maker->new('dragon', level=>$k,
    #                              part=>'blob',
    #                              undirected=>1);
    # }
    {
      # R5 k=2 not
      # Dragon k=4..5 not
      # Terdragon k=2..3 not
      #   k=2  https://hog.grinvin.org/ViewGraphInfo.action?id=21138
      #   k=3  https://hog.grinvin.org/ViewGraphInfo.action?id=21140
      #   cf k=2 not same as boat 8 vertices of Christophe et al Graphedron
      #        *---*
      #         \
      #      *---*
      #       \ / \
      #        *---*
      #         \
      #      *---*
      # AlternatePaper k=3..5 not
      # CCurve k=4..5 not
      require Graph::Maker::PlanePath;
      $graph = Graph::Maker->new('planepath',
                                 undirected=>1,
                                 level=>$k,
                                 planepath=>'TerdragonCurve');
    }

    # UlamWarburton depth=2..3 not
    # UlamWarburton,parts=2 depth=3..4 not
    #  depth=2 https://hog.grinvin.org/ViewGraphInfo.action?id=816
    # UlamWarburton,parts=1 depth=3..4 not
    #  depth=4 same as SierpinskiTriangle depth=4
    # UlamWarburton,parts=octant depth=5..6 not
    # LCornerTree,parts=2 depth=3..4 not
    #  depth=2 https://hog.grinvin.org/ViewGraphInfo.action?id=452
    # ToothpickUpist depth=6 not
    # ToothpickTree depth=3..5 not
    # ToothpickTree,parts=1 depth=4..5 not
    # ToothpickTree,parts=2 depth=4..5 not
    # ToothpickTree,parts=octant depth=5..7 not
    # ToothpickTree,parts=wedge depth=5..7 not
    # OneOfEightTree,parts=4 depth=2..3 not
    # OneOfEightTree,parts=1 depth=3..4 not
    #  depth=1 fork https://hog.grinvin.org/ViewGraphInfo.action?id=30
    # OneOfEightTree,parts=octant depth=4..5 not
    #  depth=3 https://hog.grinvin.org/ViewGraphInfo.action?id=792
    # ComplexPlus neighbours4 level=4 not
    #  level=3 https://hog.grinvin.org/ViewGraphInfo.action?id=700
    # Flowsnake neighbours6 level=1..2 not
    # FlowsnakeCentres neighbours6 level=1..2 not
    #   level=1 would be wheel 7
    # KochCurve neighbours6 level=2 not
    #   k=1 triangle+sides https://hog.grinvin.org/ViewGraphInfo.action?id=240
    #   also is SierpinskiTriangle rows 0 to 4 connected
    # SierpinskiTriangle depth=3,5,6,7 not
    #  depth=4 https://hog.grinvin.org/ViewGraphInfo.action?id=278 [done]
    #  neighbours6 level=2,3 not
    #  neighbours cf Hanoi graph H2
    # {
    #   $graph = Graph::Maker->new('planepath',
    #                              undirected=>1,
    #                              # level=>$k,
    #                              depth=>$k,
    #                              planepath=>'SierpinskiTriangle',
    #                              type => 'neighbours6',
    #                             );
    # }

    # {
    #   # BalancedTree
    #   # binary not 4,5
    #   #   height=3 https://hog.grinvin.org/ViewGraphInfo.action?id=498
    #   # ternary not 4
    #   #   height=3 https://hog.grinvin.org/ViewGraphInfo.action?id=662
    #   # quad tree not 4
    #   require Graph::Maker::BalancedTree;
    #   $graph = Graph::Maker->new('balanced_tree',
    #                              fan_out => 2, height => $k,
    #                             );
    # }
    # {
    #   # Hypercube
    #   # N=3 cubical https://hog.grinvin.org/ViewGraphInfo.action?id=1022
    #   # N=4 tesseract https://hog.grinvin.org/ViewGraphInfo.action?id=1340
    #   # N=5 not  32 nodes 80 edges
    #   require Graph::Maker::Hypercube;
    #   $graph = Graph::Maker->new('hypercube', N => $k, undirected=>1);
    # }
    # {
    #   # FibonacciTree not 5,6
    #   # k=4 six with a leaf off it
    #   #     https://hog.grinvin.org/ViewGraphInfo.action?id=934
    #   # zero_node=>1 not 4,5,6
    #   require Graph::Maker::FibonacciTree;
    #   $graph = Graph::Maker->new('fibonacci_tree',
    #                              height => $k,
    #                              # leaf_reduced => 1,
    #                              # series_reduced => 1,
    #                             );
    # }

    # Graph_branch_reduce($graph);

    # next if $graph->vertices == 0;
    last if $graph->vertices > 200;

    push @graphs, $graph;
  }
  hog_searches_html(@graphs);
  exit 0;
}

{
  # Hanoi
  # N=2  https://hog.grinvin.org/ViewGraphInfo.action?id=21136
  # N=3,4 hog not
  require Graph::Maker::Hanoi;
  my @graphs;
  foreach my $N (0 .. 3) {
    my $graph = Graph::Maker->new('hanoi', N => $N,
                                  undirected => 1,
                                 );
    # Graph_view($graph);
    push @graphs, $graph;
  }
  hog_searches_html(@graphs);
  exit 0;
}
{
  # trees symmetric and symmetric halves all the way down
  #
  # same vertex in each
  # (1,) 1,2,8,64,1024    = 2^(n(n-1)/2)
  # not 65536=2^16=64*2^10, only 1024=2^10 unique
  # same vertex, leaf = path only
  # same vertex, degree <=2
  #      1,2,7,36,587,14834
  #
  # same eccentricity
  # 1,   1,2,9,122,5894,
  # same eccentricity, degree <=2
  #      1,2,8, 80,2210,
  #

  my $connect_max_degree = 0;
  my $connect_at_same = 1;

  $| = 1;
  Graph::Graph6::write_graph(filename  => '/tmp/1.s6',
                             edge_aref => [ [0,1] ],
                             format    => 'sparse6',
                            );
  foreach my $i (1 .. 10) {
    # if ($i == 4) {
    #   my @graphs;
    #   open my $fh, '<', "/tmp/$i.s6" or die;
    #   require Graph::Reader::Graph6;
    #   my $reader = Graph::Reader::Graph6->new;
    #   while (my $graph = $reader->read_graph($fh)) {
    #     push @graphs, $graph;
    #   }
    #   hog_searches_html(@graphs);
    #   exit;
    # }

    my $num_vertices;
    my @edges;
    open my $fh, '<', "/tmp/$i.s6" or die;
    open my $out, '>', "/tmp/new.s6" or die;
    my $count = 0;
    while (Graph::Graph6::read_graph(fh               => $fh,
                                     num_vertices_ref => \$num_vertices,
                                     edge_aref        => \@edges,
                                    )) {
      $count++;
      print "$count\r";

      my @eccentricity = map {edge_aref_eccentricity(\@edges,$_)}
        0 .. scalar(@edges);
      ### @eccentricity

      # two copies, with $new_edges[0] dummy to be changed
      my @new_edges = ([-1,-1],
                       @edges,
                       map {[ $_->[0]+$num_vertices, $_->[1]+$num_vertices ]}
                       @edges);

      foreach my $v (0 .. $num_vertices-1) {
        $new_edges[0]->[0] = $v;
        next if ($connect_max_degree
                 && edge_aref_vertex_degree(\@edges, $v) > $connect_max_degree);

        foreach my $v2 ($connect_at_same ? ($v) : (0 .. $num_vertices-1)) {
        next if ($connect_max_degree
                 && edge_aref_vertex_degree(\@edges, $v2) > $connect_max_degree);

          if ($eccentricity[$v] == $eccentricity[$v2]) {
            $new_edges[0]->[1] = $v2 + $num_vertices;
            Graph::Graph6::write_graph(fh        => $out,
                                       edge_aref => \@new_edges,
                                       format    => 'sparse6',
                                      );
          }
        }
      }
    }
    print "k=$i  v=$num_vertices  uniq $count\n";

    IPC::Run::run(['nauty-labelg'],
                  '<', '/tmp/new.s6',
                  '|', ['sort','-u'],
                  '|', ['tee', '/tmp/'.($i+1).'.s6'],
                  '|', ['wc','-l']);
  }
  exit 0;

  sub edge_aref_vertex_is_leaf {
    my ($edge_aref, $v) = @_;
    my $count = 0;
    foreach my $edge (@$edge_aref) {
      $count += ($edge->[0] == $v);
      $count += ($edge->[1] == $v);
      if ($count > 1) { return 0; }
    }
    return 1;
  }
  sub edge_aref_vertex_degree {
    my ($edge_aref, $v) = @_;
    return scalar((  grep {$_->[0] == $v} @$edge_aref)
                  + (grep {$_->[1] == $v} @$edge_aref));
  }
}


{
  # graph G*(n) with all small subtrees

  # d(k) = floor((n+k-1)/k);
  # Gedges(n) = 1/2*sum(k=1,n+1, ceil(n/k));
  # ceil(vector(20,n,Gedges(n)))

  # edges=1  <= 1
  # >A /usr/bin/nauty-geng -cd1D1 n=2 e=1
  # >Z 1 graphs generated in 0.00 sec
  #   0-1 [1 edges]  vertices=2
  # edges=2  <= 2
  # >A /usr/bin/nauty-geng -cd1D2 n=3 e=2
  # >Z 1 graphs generated in 0.00 sec
  #   0-2,1-2 [2 edges]  vertices=3
  #
  # edges=3  <= 4
  # >A /usr/bin/nauty-geng -cd1D3 n=4 e=3-4
  # >Z 4 graphs generated in 0.00 sec
  #   0-2,0-3,1-3,2-3 [4 edges]  vertices=4
  #   https://hog.grinvin.org/ViewGraphInfo.action?id=646
  # 2 subtrees, 4-path, 4-star=claw
  #                    *                     *
  #                    |          graph    / |
  #   *--*--*--*    *--*--*               *--*--*
  #                     
  # edges=4  <= 6
  # >A /usr/bin/nauty-geng -cd1D4 n=5 e=4-6
  # >Z 13 graphs generated in 0.00 sec
  #   0-3,1-3,0-4,1-4,2-4,3-4 [6 edges]  vertices=5
  #     https://hog.grinvin.org/ViewGraphInfo.action?id=1026  dart graph
  #   0-2,1-3,0-4,1-4,2-4,3-4 [6 edges]  vertices=5
  #     https://hog.grinvin.org/ViewGraphInfo.action?id=776   bowtie/hourglass
  # 3 subtrees
  #   *--*--*--*--*
  #                   
  #      *            *   * bowtie        0     dart 
  #      |            |\ /|              / \
  #   *--*--*--*      | * |             3---4--2
  #                   |/ \|              \ /
  #      *            *   *               1
  #      |      
  #   *--*--*
  #      |      
  #      *      
  #
  # edges=5  <= 8
  # >A /usr/bin/nauty-geng -cd1D5 n=6 e=5-8
  # >Z 60 graphs generated in 0.00 sec
  #   0-3,0-4,1-4,0-5,1-5,2-5,3-5,4-5 [8 edges]  vertices=6 
  #     https://hog.grinvin.org/ViewGraphInfo.action?id=860
  #   0-3,1-4,2-4,0-5,1-5,2-5,3-5,4-5 [8 edges]  vertices=6 [Shown]
  #     hog not
  #     https://hog.grinvin.org/ViewGraphInfo.action?id=21132
  # 6 subtrees
  #       
  # 1-3,2-4,3-4,0-5,1-5,2-5,3-5,4-5 [8 edges]  vertices=6
  # 2-3,0-4,1-4,0-5,1-5,2-5,3-5,4-5 [8 edges]  vertices=6 [Shown]
  #       *   *          *     *
  #      / \ /           | \ / |
  #     *---*            *--*--*
  #      \ / \           | /
  #       *---*          *
  #   
  #
  # edges=6  <= 11
  # >A /usr/bin/nauty-geng -cd1D6 n=7 e=6-11
  # >Z 488 graphs generated in 0.00 sec
  #   2-4,3-4,1-5,2-5,3-5,0-6,1-6,2-6,3-6,4-6,5-6 [11 edges]  vertices=7
  #   2-3,3-4,0-5,1-5,4-5,0-6,1-6,2-6,3-6,4-6,5-6 [11 edges]  vertices=7
  #   1-4,3-4,2-5,3-5,4-5,0-6,1-6,2-6,3-6,4-6,5-6 [11 edges]  vertices=7
  #   1-3,2-4,0-5,3-5,4-5,0-6,1-6,2-6,3-6,4-6,5-6 [11 edges]  vertices=7
  #   1-2,3-4,2-5,3-5,4-5,0-6,1-6,2-6,3-6,4-6,5-6 [11 edges]  vertices=7
  #   1-2,3-4,0-5,3-5,4-5,0-6,1-6,2-6,3-6,4-6,5-6 [11 edges]  vertices=7 [Shown]
  #   2-3,0-4,2-4,1-5,3-5,0-6,1-6,2-6,3-6,4-6,5-6 [11 edges]  vertices=7
  #   7 of
  #
  # edges=7  <= 13
  # >A /usr/bin/nauty-geng -cd1D7 n=8 e=7-13
  # >Z 4271 graphs generated in 0.01 sec
  #   3-4,1-5,3-5,2-6,4-6,5-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8 [shown]
  #   2-4,3-5,4-5,0-6,1-6,3-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   2-4,3-5,4-5,1-6,2-6,3-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #
  #   0-4,0-5,1-5,0-6,1-6,2-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-4,0-5,1-5,1-6,2-6,3-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-4,0-5,1-5,1-6,2-6,4-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-4,1-5,2-5,0-6,1-6,2-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-4,1-5,2-5,0-6,1-6,3-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-4,1-5,2-5,1-6,2-6,3-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-4,1-5,2-5,0-6,1-6,4-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-4,1-5,2-5,0-6,3-6,4-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-4,1-5,2-5,0-6,1-6,5-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-4,1-5,2-5,0-6,3-6,5-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-4,1-5,2-5,1-6,3-6,5-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-3,1-4,2-5,0-6,1-6,2-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  #   0-3,1-4,2-5,0-6,1-6,3-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]  vertices=8
  # 13 of

  #                    0  1  2  3  4  5   6   7
  my @num_edges_max = (0, 1, 2, 4, 6, 8, 11, 13);
  my @graphs;
  foreach my $num_edges (5,
                         # 1 .. 5
                        ) {
    my $num_edges_max = $num_edges_max[$num_edges];
    print "edges=$num_edges  <= $num_edges_max\n";
    my @subtree_edge_arefs;
    {
      my $iterator_func = make_tree_iterator_edge_aref
        (num_vertices => $num_edges+1);
      while (my $subtree_edge_aref = $iterator_func->()) {
        push @subtree_edge_arefs, $subtree_edge_aref;
      }
      my $num_subtrees = scalar(@subtree_edge_arefs);
      print "  $num_subtrees subtrees\n";
      if ($num_subtrees < 8) {
        foreach my $subtree_edge_aref (@subtree_edge_arefs) {
          print "    ",edge_aref_string($subtree_edge_aref),"\n";
          if ($num_edges == 3) {
            Graph_Easy_view(Graph_Easy_from_edge_aref($subtree_edge_aref));
          }
        }
      }
    }
    my $count = 0;
    $| = 1;
    my $iterator_func = make_graph_iterator_edge_aref
      (num_vertices => $num_edges+1,
       num_edges_min => $num_edges,
       num_edges_max => $num_edges_max);
  TREE: while (my $edge_aref = $iterator_func->()) {
      $count++;
      print "$count ($#$edge_aref)\r";
      foreach my $subtree_edge_aref (@subtree_edge_arefs) {
        if (! edge_aref_is_subgraph($edge_aref, $subtree_edge_aref)) {
          next TREE;
        }
      }
      my $easy = Graph_Easy_from_edge_aref($edge_aref);
      my $num_vertices = $easy->vertices;
      print "  ",edge_aref_string($edge_aref),"  vertices=$num_vertices\n";
      # if ($num_edges == 5) {
      #   Graph_Easy_view(Graph_Easy_from_edge_aref($edge_aref));
      # }
      $easy->set_attribute (label => "vertices=$num_vertices");
      push @graphs, $easy;
    }
  }
  hog_searches_html(@graphs);
  exit 0;
}

{
  # Chung and Graham graphs n=6,7 containing all subtrees
  #
  # 1-2,3-4,0-5,3-5,4-5,0-6,1-6,2-6,3-6,4-6,5-6 [11 edges]
  # 3-4,1-5,3-5,2-6,4-6,5-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7 [13 edges]

  my @graphs;
  my @g6_strs;
  my $writer = Graph::Writer::Graph6->new;
  require Graph::Writer::Graph6;
  {
    # n=6
    # https://hog.grinvin.org/ViewGraphInfo.action?id=21128
    #         2    6
    #       / | \ / \
    #      1-----4---7
    #       \ | / \
    #         3----5
    my $graph = Graph->new(undirected=>1);
    $graph->add_edges(1,2, 1,3, 1,4,
                      2,3, 2,4,
                      3,2, 3,4, 3,5,
                      4,5, 4,6, 4,7,
                      6,7);
    push @graphs, $graph;
    open my $fh, '>', \$g6_strs[0] or die;
    $writer->write_graph($graph, $fh);
  }
  {
    # n=7
    # https://hog.grinvin.org/ViewGraphInfo.action?id=21130
    #         3---5
    #       / | \ |
    #      1---__\|
    #      |  |__ 6---8
    #      2---  /|
    #       \ | / |
    #         4---7
    my $graph = Graph->new(undirected=>1);
    $graph->add_edges(1,2, 1,3, 1,6,
                      2,4, 2,6,
                      3,4, 3,5, 3,6,
                      4,6, 4,7,
                      5,6, 6,7, 6,8);
    push @graphs, $graph;
    open my $fh, '>', \$g6_strs[1] or die;
    $writer->write_graph($graph, $fh);
  }

  foreach my $g6_str (@g6_strs) {
    $g6_str = graph6_str_to_canonical($g6_str);
    my $edge_aref = [];
    Graph::Graph6::read_graph(str => $g6_str,
                              edge_aref => $edge_aref) or die;
    print edge_aref_string($edge_aref),"\n";
    push @graphs, $edge_aref;
  }

  hog_searches_html(@graphs);
  exit 0;
}




{
  # terminal Wiener maximum on trees

  require Graph::Reader::Graph6;
  my $reader = Graph::Reader::Graph6->new;
  $| = 1;
  foreach my $n (13) {
    my @graphs;
    my $filename = sprintf "$ENV{HOME}/HOG/trees%02d.g6", $n;
    open my $fh, '<', $filename or die "cannot open $filename: $!";
    my $max = 0;
    my @max_graphs;
    while (my $graph = $reader->read_graph($fh)) {
      # next unless Graph_num_terminal_vertices($graph) == 8;
      my $TW = Graph_terminal_Wiener_index($graph);
      if ($TW == $max) {
        push @max_graphs, $graph;
      }
      if ($TW > $max) {
        $max = $TW;
        @max_graphs = ($graph);
      }
    }
    my $max_graphs_count = scalar(@max_graphs);
    print "n=$n  $max (count $max_graphs_count)\n";
    # print "$max,";
    foreach my $graph (@max_graphs) {
      $graph->set_graph_attribute (name => "n=$n");
      Graph_view($graph);
    }
  }
  exit 0;

  sub Graph_num_terminal_vertices {
    my ($graph) = @_;
    my $count = grep {$graph->vertex_degree($_)==1} $graph->vertices;
    return $count;
  }
}

{
  # Gutman, Furtula, Petrovic n=12 vertices
  # maximum terminal Wiener index for k terminals
  #
  my @graphs;
  require Graph::Maker::Caterpillar;
  {
    # n=10 equal maximum  caterpillar 5,5
    # https://hog.grinvin.org/ViewGraphInfo.action?id=112
    my $graph = Graph::Maker->new('caterpillar', N_list=>[5,5], undirected=>1);
    $graph->set_graph_attribute (name => "n=10");
    $graph->set_graph_attribute('flow','east');
    push @graphs, $graph;
  }
  {
    # n=10 equal maximum  star 10
    # https://hog.grinvin.org/ViewGraphInfo.action?id=34
    require Graph::Maker::Star;
    my $graph = Graph::Maker->new('star', N=>10, undirected=>1);
    $graph->set_graph_attribute (name => "n=10");
    $graph->set_graph_attribute('flow','east');
    push @graphs, $graph;
  }

  {
    # n=11 unique maximum
    # is n=3*s+2 for s=3, case d k=2*s+3=9 pendent, ceil((s-1)/2)=1 of
    #
    # https://hog.grinvin.org/ViewGraphInfo.action?id=650
    my $graph = Graph::Maker->new('caterpillar', N_list=>[6,5],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=11");
    $graph->set_graph_attribute('flow','east');
    push @graphs, $graph;
  }

  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[3,1,1,1,1,1,1,3],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=4");
    $graph->set_graph_attribute('flow','east');
    push @graphs, $graph;
  }

  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[4,1,1,1,1,1,3],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=5");
    push @graphs, $graph;
  }
  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[3,2,1,1,1,1,3],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=5");
    push @graphs, $graph;
  }
  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[3,1,2,1,1,1,3],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=5");
    push @graphs, $graph;
  }
  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[3,1,1,2,1,1,3],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=5");
    push @graphs, $graph;
  }

  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[4,1,1,1,1,4],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=6");
    push @graphs, $graph;
  }

  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[5,1,1,1,4],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=7");
    push @graphs, $graph;
  }
  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[4,2,1,1,4],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=7");
    push @graphs, $graph;
  }
  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[4,1,2,1,4],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=7");
    push @graphs, $graph;
  }

  {
    # unique maximum n=12 k=8
    # https://hog.grinvin.org/ViewGraphInfo.action?id=426
    my $graph = Graph::Maker->new('caterpillar', N_list=>[5,1,1,5],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=8");
    push @graphs, $graph;
  }

  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[6,1,5],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=9");
    push @graphs, $graph;
  }
  {
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[5,2,5],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=9");
    push @graphs, $graph;
  }

  {
    # n=12 k=10 caterpillar 6,6 is overall maximum
    # https://hog.grinvin.org/ViewGraphInfo.action?id=36
    my $graph = Graph::Maker->new('caterpillar', N_list=>[6,6],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=12 k=10");
    push @graphs, $graph;
  }

  {
    # n=13 A
    # https://hog.grinvin.org/ViewGraphInfo.action?id=80
    my $graph = Graph::Maker->new('caterpillar', N_list=>[6,1,6],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=13 A");
    push @graphs, $graph;
  }
  {
    # n=13 B
    # https://hog.grinvin.org/ViewGraphInfo.action?id=38
    my $graph = Graph::Maker->new('caterpillar', N_list=>[7,6],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=13 B");
    push @graphs, $graph;
  }

  {
    # n=14 A
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[7,1,6],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=14 A");
    push @graphs, $graph;
  }
  {
    # n=14 B
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[6,2,6],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=14 B");
    push @graphs, $graph;
  }

  {
    # n=15
    # https://hog.grinvin.org/ViewGraphInfo.action?id=200
    my $graph = Graph::Maker->new('caterpillar', N_list=>[7,1,7],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=15");
    push @graphs, $graph;
  }

  {
    # n=16 A
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[7,1,1,7],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=16 A");
    push @graphs, $graph;
  }
  {
    # n=16 B
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[8,1,7],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=16 B");
    push @graphs, $graph;
  }
  {
    # n=16 C
    # hog not
    my $graph = Graph::Maker->new('caterpillar', N_list=>[7,2,7],
                                  undirected=>1);
    $graph->set_graph_attribute (name => "n=16 C");
    push @graphs, $graph;
  }


  hog_searches_html(@graphs);
  exit 0;
}

{
  {  # Star with N=0
    require Graph::Maker::Star;
    my $graph = Graph::Maker->new('star', N=>0, undirected=>1);
    my $num_vertices = $graph->vertices;
    print "N=0 num_vertices=$num_vertices  $graph\n";
  }
  {
    # Star with N=1
    require Graph::Maker::Star;
    my $graph = Graph::Maker->new('star', N=>1,
                                  undirected=>1,
                                 );
    my $num_vertices = $graph->vertices;
    my $num_edges = $graph->edges;
    print "N=1 num_vertices=$num_vertices num_edges=$num_edges  $graph\n";
  }
  exit 0;
}

{
  # Chung and Graham graph containing all subtrees
  my @graphs;
  foreach my $str (
                   # # [11 edges]  vertices=7
                   # 
                   # # hog not
                   # '0-4,1-4,0-5,1-5,2-5,0-6,1-6,2-6,3-6,4-6,5-6',
                   # 
                   # # hog not
                   # '0-4,1-4,0-5,2-5,3-5,0-6,1-6,2-6,3-6,4-6,5-6',
                   # 
                   # # https://hog.grinvin.org/ViewGraphInfo.action?id=784
                   # '0-4,1-4,0-5,2-5,4-5,0-6,1-6,2-6,3-6,4-6,5-6',
                   # 
                   # # hog not
                   # '0-3,1-4,0-5,1-5,2-5,0-6,1-6,2-6,3-6,4-6,5-6',
                   # 
                   # # hog not
                   # '0-3,1-4,0-5,1-5,3-5,0-6,1-6,2-6,3-6,4-6,5-6',
                   # 
                   # # hog not, this one from Chung and Graham
                   # '0-3,1-4,0-5,2-5,3-5,0-6,1-6,2-6,3-6,4-6,5-6',
                   # 
                   # # hog not
                   # '0-3,0-4,1-4,1-5,2-5,0-6,1-6,2-6,3-6,4-6,5-6',


                   # hog not
                   '0-4,0-5,1-5,0-6,1-6,2-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',

                   '0-4,0-5,1-5,1-6,2-6,3-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-4,0-5,1-5,1-6,2-6,4-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-4,1-5,2-5,0-6,1-6,2-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-4,1-5,2-5,0-6,1-6,3-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-4,1-5,2-5,1-6,2-6,3-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-4,1-5,2-5,0-6,1-6,4-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-4,1-5,2-5,0-6,3-6,4-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-4,1-5,2-5,0-6,1-6,5-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-4,1-5,2-5,0-6,3-6,5-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-4,1-5,2-5,1-6,3-6,5-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-3,1-4,2-5,0-6,1-6,2-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   '0-3,1-4,2-5,0-6,1-6,3-6,0-7,1-7,2-7,3-7,4-7,5-7,6-7',
                   # 13 of
                  ) {
    push @graphs, edge_aref_string_to_edge_aref($str);
  }
  hog_searches_html(@graphs);
  exit 0;

  sub edge_aref_string_to_edge_aref {
    my ($str) = @_;
    return [ map {[split /-/, $_]} split /,/, $str ];
  }
}

{
  # subtrees n=7 edges
  # hog not
  my $easy = Graph::Easy->new (undirected => 1);
  $easy->add_edge(0,1);
  $easy->add_edge(1,2);
  $easy->add_edge(2,3);
  $easy->add_edge(3,4);$easy->add_edge(3,5);
  $easy->add_edge(5,6);$easy->add_edge(5,7);
  $easy->add_edge(5,8);$easy->add_edge(5,9);
  $easy->add_edge(5,10);$easy->add_edge(5,11);
  $easy->add_edge(10,12);
  $easy->add_edge(11,13);$easy->add_edge(11,14);$easy->add_edge(11,15);
  $easy->add_edge(15,16);$easy->add_edge(15,17);
  hog_searches_html($easy);
  exit 0;
}
{
  # subtrees n=6 edges
  # hog not
  my $easy = Graph::Easy->new (undirected => 1);
  $easy->add_edge(0,1);
  $easy->add_edge(1,2);
  $easy->add_edge(2,3);$easy->add_edge(2,4);
  $easy->add_edge(4,5);$easy->add_edge(4,6);
  $easy->add_edge(6,7);$easy->add_edge(6,8);$easy->add_edge(6,9);
  $easy->add_edge(6,10);$easy->add_edge(6,11);
  $easy->add_edge(10,12);
  $easy->add_edge(11,13);
  hog_searches_html($easy);
  exit 0;
}


{
  # terminal Wiener / diameter range
  # maximum is star
  require Graph::Reader::Graph6;
  my $reader = Graph::Reader::Graph6->new;
  $| = 1;
  foreach my $n (4 .. 20) {
    my @graphs;
    my $filename = sprintf "$ENV{HOME}/HOG/trees%02d.g6", $n;
    open my $fh, '<', $filename or die "cannot open $filename: $!";
    my $min = 1e50;
    my $max = 0;
    my @max_graphs;
    while (my $graph = $reader->read_graph($fh)) {
      my $mean = Graph_terminal_Wiener_index($graph) / $graph->diameter;
      # print $mean,"\n";
      $min = min($min, $mean);
      if ($mean > $max) {
        $max = $mean;
        push @max_graphs, $graph;
      }
    }
    my $max_graphs_count = scalar(@max_graphs);
    print "n=$n  $min  $max($max_graphs_count)\n";
    # print "$max,";
    foreach my $graph (@max_graphs) {
      $graph->set_graph_attribute (name => "n=$n");
      Graph_view($graph);
    }
  }
  exit 0;
}
{
  # Wiener of line graph
  foreach my $k (2 .. 15) {
    # require Graph::Maker::Star;
    # my $graph = Graph::Maker->new('star', N=>$k, undirected=>1);

    # require Graph::Maker::Linear;
    # my $graph = Graph::Maker->new('linear', N=>$k, undirected=>1);

    # require Graph::Maker::BalancedTree;
    # my $graph = Graph::Maker->new('balanced_tree',
    #                               fan_out => 2, height => $k,
    #                               undirected=>1,
    #                              );

    # require Graph::Maker::FibonacciTree;
    # my $graph = Graph::Maker->new('fibonacci_tree',
    #                               height => $k,
    #                               # leaf_reduced => 1,
    #                               # series_reduced => 1,
    #                               undirected=>1,
    #                              );

    # require Graph::Maker::BinomialTree;
    # my $graph = Graph::Maker->new('binomial_tree',
    #                               order => $k,
    #                               undirected => 1,
    #                              );

    require Graph::Maker::TwindragonAreaTree;
    my $graph = Graph::Maker->new('twindragon_area_tree',
                                  level => $k,
                                  undirected => 1,
                                 );
    print "k=$k\n";
    if ($graph->vertices <= 16) { print "$graph\n"; }
    my $first;
    for (;;) {
      my $W = Graph_Wiener_index($graph);
      print "  W=$W\n";
      $first //= $W;
      last if $W > $first;
      last if $W == 0;
      $graph = Graph_line_graph($graph);
    }
  }
  exit 0;
}
{
  # some geometric-arithmetic mean

  require Math::BigRat;
  foreach my $k (2 .. 15) {
    # require Graph::Maker::Star;
    # my $graph = Graph::Maker->new('star', N=>$k, undirected=>1);

    # require Graph::Maker::Linear;
    # my $graph = Graph::Maker->new('linear', N=>$k, undirected=>1);

    # require Graph::Maker::BalancedTree;
    # my $graph = Graph::Maker->new('balanced_tree',
    #                               fan_out => 2, height => $k,
    #                               undirected=>1,
    #                              );

    # require Graph::Maker::FibonacciTree;
    # my $graph = Graph::Maker->new('fibonacci_tree',
    #                               height => $k,
    #                               # leaf_reduced => 1,
    #                               # series_reduced => 1,
    #                               undirected=>1,
    #                              );

    require Graph::Maker::BinomialTree;
    my $graph = Graph::Maker->new('binomial_tree',
                                  order => $k,
                                  undirected => 1,
                                 );

    my %degrees = map {$_ => $graph->vertex_degree($_)} $graph->vertices;
    my $total;
    my $num_edges = 0;
    my %count_types;
    my @total_by_sqrt;
    foreach my $edge ($graph->edges) {
      my $d1 = $degrees{$edge->[0]};
      my $d2 = $degrees{$edge->[1]};
      my $num = $d1 * $d2;
      my $den = $d1 + $d2;
      if ($den) {
        $total += 2* sqrt($num) / $den;
      }
      $num_edges++;
      if ($d1 > $d2) { ($d1,$d2) = ($d2,$d1) }
      # $count_types{"$d1,$d2"}++;
      ### $num
      ### $den
      $count_types{"$num/$den"}++;
      if ($den) {
        $total_by_sqrt[$num] ||= 0;
        $total_by_sqrt[$num] += Math::BigRat->new("2/$den");
      }
    }
    ### $num_edges
    my $f = ($num_edges ? $total / $num_edges : "no edges");
    print "$k total=$total  mean=$f\n";
    foreach my $num (1 .. $#total_by_sqrt) {
      if ($total_by_sqrt[$num]) {
        print "  $num $total_by_sqrt[$num]\n";
      }
    }
  }
  exit 0;
}



{
  # Chung, Graham, Pippenger all small subtrees

  # edges=4 is 3 subtrees, count 2 with all
  #       *                 *            *--*--*--*--*     *
  #       |                 |                              |
  # *--*--*--*--*  *--*--*--*--*         *--*--*--*     *--*--*
  #       |                 |                  |           |
  #       *                 *                  *           *
  #
  # edges=5 is 6 subtrees, count 3 with all
  #     *   *  (A)                 *   *  (C)         (B)      *   *
  #     |   |                      |   |                       |   |
  # *---*---*---*---*---*  *---*---*---*---*---*   *---*---*---*---*---*
  #    / \                        / \                         / \
  #   *   *                      *   *                       *   *
  #
  # edges=6 is 11 subtrees
  #
  #   *   *     *   *        *   *              *   *        *   *   *
  #    \ /       \ /          \ /                \ /          \ /   /
  #  *--*--*   *--*--*--*   *--*--*--*--*   *--*--*--*--*   *--*---*--*
  #    / \       /
  #   *   *     *
  #                         *                     *
  #                         |                     |
  #  *--*--*--*--*--*    *--*--*--*--*--*   *--*--*--*--*--*
  #
  #     *  *            *     *            *--*
  #     |  |            |     |            |
  #  *--*--*--*--*   *--*--*--*--*   *--*--*--*--*
  #
  #
  # edges=3, unique
  # https://hog.grinvin.org/ViewGraphInfo.action?id=30
  #
  # edges=4, 2 of
  # example shown https://hog.grinvin.org/ViewGraphInfo.action?id=792
  # other not
  #
  # edges=5, 3 of
  # I????SE{G not
  # I????cKwg not
  # I???G_Hwg not
  #
  # edges=6, 19 of
  # 0-10,1-10,0-11,2-11,3-12,4-12,5-12,0-13,3-13,6-13,7-13,8-13,9-13 [13 edges]
  # 0-10,1-10,2-11,3-11,0-12,4-12,5-12,0-13,2-13,6-13,7-13,8-13,9-13 [13 edges]
  # 0-10,1-10,2-11,3-11,4-12,5-12,6-12,2-13,4-13,7-13,8-13,9-13,10-13 [13 edges]
  # 0-9,1-10,0-11,2-11,2-12,3-12,4-12,1-13,2-13,5-13,6-13,7-13,8-13 [13 edges]
  # 0-9,1-10,0-11,2-11,2-12,3-12,4-12,1-13,5-13,6-13,7-13,8-13,11-13 [13 edges]
  # 0-9,1-10,0-11,2-11,3-12,4-12,5-12,0-13,1-13,3-13,6-13,7-13,8-13 [13 edges]
  # 0-9,1-10,2-11,3-11,0-12,1-12,4-12,4-13,5-13,6-13,7-13,8-13,11-13 [13 edges]
  # 0-9,1-10,2-11,3-11,0-12,2-12,4-12,1-13,2-13,5-13,6-13,7-13,8-13 [13 edges]
  # 0-9,1-10,2-11,3-11,0-12,4-12,5-12,0-13,1-13,2-13,6-13,7-13,8-13 [13 edges]
  # 0-9,1-10,2-11,3-11,0-12,4-12,5-12,1-13,4-13,6-13,7-13,8-13,11-13 [13 edges]
  # 0-9,1-10,2-11,3-11,2-12,4-12,5-12,0-13,1-13,6-13,7-13,8-13,11-13 [13 edges]
  # 0-9,0-10,1-10,1-11,2-11,3-12,4-12,1-13,5-13,6-13,7-13,8-13,12-13 [13 edges]
  # 0-9,0-10,1-10,2-11,3-11,4-12,5-12,0-13,4-13,6-13,7-13,8-13,11-13 [13 edges]
  # 0-9,0-10,1-10,2-11,3-11,4-12,5-12,1-13,6-13,7-13,8-13,11-13,12-13 [13 edges]
  # 0-9,1-10,2-10,1-11,3-11,0-12,4-12,0-13,1-13,5-13,6-13,7-13,8-13 [13 edges]
  # 0-9,1-10,2-10,1-11,3-11,4-12,5-12,0-13,6-13,7-13,8-13,10-13,12-13 [13 edges]
  # 0-8,1-9,2-10,3-11,0-12,1-12,2-12,0-13,3-13,4-13,5-13,6-13,7-13 [13 edges]
  # 0-8,1-9,2-10,3-11,0-12,1-12,4-12,0-13,2-13,3-13,5-13,6-13,7-13 [13 edges]
  # 0-8,1-9,2-10,0-11,3-11,1-12,4-12,0-13,1-13,2-13,5-13,6-13,7-13 [13 edges]
  #
  #           count                2  3
  #           edges    0  1  2  3  4  5   6   7
  my @num_edges_max = (0, 1, 2, 4, 6, 9, 13, 17);
  my @graphs;
  foreach my $num_edges (7) {
    my $num_edges_max = $num_edges_max[$num_edges];
    print "edges=$num_edges  <= $num_edges_max\n";
    my @subtree_edge_arefs;
    {
      my $iterator_func = make_tree_iterator_edge_aref
        (num_vertices => $num_edges+1);
      while (my $subtree_edge_aref = $iterator_func->()) {
        push @subtree_edge_arefs, $subtree_edge_aref;
        # print "  want ",edge_aref_string($subtree_edge_aref),"\n";
        # if ($num_edges == 6) {
        #   Graph_Easy_view(Graph_Easy_from_edge_aref($subtree_edge_aref));
        # }
      }
    }
    my $count = 0;
    $| = 1;
    my $iterator_func = make_tree_iterator_edge_aref
      (num_vertices_min => $num_edges+1,
       num_vertices_max => $num_edges_max+1);
  TREE: while (my $edge_aref = $iterator_func->()) {
      $count++;
      # print "$count ($#$edge_aref)\r";
      foreach my $subtree_edge_aref (@subtree_edge_arefs) {
        if (! edge_aref_degrees_allow_subgraph($edge_aref, $subtree_edge_aref)) {
          next TREE;
        }
      }
      foreach my $subtree_edge_aref (@subtree_edge_arefs) {
        if (! edge_aref_is_induced_subgraph($edge_aref, $subtree_edge_aref)) {
          next TREE;
        }
      }
      print "  ",edge_aref_string($edge_aref),"\n";
      # if ($num_edges == 5) {
      #   Graph_Easy_view(Graph_Easy_from_edge_aref($edge_aref));
      # }
      my $easy = Graph_Easy_from_edge_aref($edge_aref);
      $easy->set_attribute (label => "edges=$num_edges");
      push @graphs, $easy;
    }
  }
  hog_searches_html(@graphs);
  exit 0;
}
{
  my @num_edges_max = (1, 2, 4, 6, 9, 13, 17);
  require Math::OEIS::Grep;
  Math::OEIS::Grep->search(array => \@num_edges_max,
                           max_matches => undef);
  exit 0;
}
{
  # average_path_length() / diameter
  #
  # W Fibonacci tree = W(k-1) + W(k-2) + F(k+1)*D(k-2) + F(k)*D(k-1) + F(k+1)F(k)
  #
  # A165910 Wiener of Fibonacci tree 1, 4, 18, 62, 210   connect roots
  # A180567 Wiener of Fibonacci tree 0, 0, 4, 18, 96   F(-1)=F(0)=single node
  # A192019 Wiener of binary Fibonacci tree  F(0)=empty F(1)=single node
  #
  #--------------------
  # linear
  # *--*--*--*
  # n=4; sum(i=1,n-1, i) == n*(n-1)/2
  # 2*sum(n=2,N, n*(n-1)/2) = (N-1)*(N)*(N+1)/3  \\ 2*tetrahedral
  # (N-1)*(N)*(N+1)/3 / (N-1) / N^2 -> 1/3
  #
  #--------------------
  # star
  #    *
  #    |
  # *--*--*
  # total path length (N-1)*(1 + 2*(N-2)) + (N-1) == 2*(N-1)^2
  # diameter = 2
  # average = 2*(N-1)^2 / 2 / N^2 -> 1
  #
  #----------
  # BalancedTree
  # A158681 Wiener of complete binary tree = 4*(n-2)*4^n + 2*(n+4)*2^n
  #   = 4, 48, 368, 2304 starting n=1
  #    *    (1+2 + 2 + 1+2)/2 = 4
  #   / \   has 2^(n+1)-1 vertices
  #  *   *
  #  diameter 2*n
  # Test-Pari-DEFINE  complete_binary_Wiener(n) = 4*(n-2)*4^n + 2*(n+4)*2^n;
  # Test-Pari  complete_binary_Wiener(1) == 4
  # Test-Pari  complete_binary_Wiener(2) == 48
  # Test-Pari-DEFINE  complete_binary_vertices(n) = 2^(n+1)-1;
  # Test-Pari  complete_binary_vertices(1) == 3
  # Test-Pari-DEFINE  complete_binary_diameter(n) = 2*n;
  # Test-Pari  complete_binary_diameter(1) == 2
  # Test-Pari-DEFINE  complete_binary_mean(n) = 2*complete_binary_Wiener(n) \
  # Test-Pari-DEFINE   / complete_binary_vertices(n)^2 \
  # Test-Pari-DEFINE   / complete_binary_diameter(n);
  # Test-Pari-DEFINE  complete_binary_mean_formula(n) = \
  # Test-Pari-DEFINE    1 - 2/n + 3*1/(2*2^n - 1) + 2*(1 + 1/n)*1/(2*2^n - 1)^2;
  # Test-Pari  vector(100,n, complete_binary_mean_formula(n)) == vector(100,n, complete_binary_mean(n))
  # complete_binary_mean -> 1 slightly slowly
  #
  #----------
  # BinomialTree
  # A192021 Wiener of binomial tree = 2*n*4^n + 2^n
  # W Binomial tree = (k-1)*2^(2k-1) + 2^(k-1)
  #
  #      __0      order=2 total path=2*10 = 20
  #     /  |
  #    1   2
  #        |
  #        3
  #
  # Test-Pari-DEFINE  binomial_Wiener(n) = 2*(n-1)*4^(n-1) + 2^(n-1);
  # Test-Pari  binomial_Wiener(1) == 0
  # Test-Pari  binomial_Wiener(2) == 10
  # Test-Pari  binomial_Wiener(3) == 68
  # Test-Pari  binomial_Wiener(4) == 392
  # Test-Pari-DEFINE  binomial_vertices(n) = 2^n;
  # Test-Pari  binomial_vertices(0) == 1
  # Test-Pari  binomial_vertices(2) == 4
  # Test-Pari-DEFINE  binomial_diameter(n) = 2*n-1;
  # Test-Pari  binomial_diameter(2) == 3
  # Test-Pari-DEFINE  binomial_mean(n) = 2*binomial_Wiener(n) \
  # Test-Pari-DEFINE   / binomial_vertices(n)^2 \
  # Test-Pari-DEFINE   / binomial_diameter(n);
  # Test-Pari-DEFINE  binomial_mean_formula(n) = \
  # Test-Pari-DEFINE    ((n-1) + 1/2^n)  / (2*n-1);
  # Test-Pari  vector(100,n, binomial_mean_formula(n)) == vector(100,n, binomial_mean(n))
  # binomial_mean -> 1/2
  #
  #------
  # K. Viswanathan Iyer and Udaya Kumar Reddy K.R, "Wiener index of
  # binomial trees and Fibonacci trees", arxiv:0910.4432 getting

  require Graph::Maker::Star;
  require Graph::Maker::Linear;
  foreach my $k (2..15) {
    # my $graph = Graph::Maker->new('star', N=>$k, undirected=>1);
    # my $graph = Graph::Maker->new('linear', N=>$k, undirected=>1);

    # require Graph::Maker::BalancedTree;
    # my $graph = Graph::Maker->new('balanced_tree',
    #                               fan_out => 2, height => $k,
    #                              );

    require Graph::Maker::FibonacciTree;
    my $graph = Graph::Maker->new('fibonacci_tree',
                                  height => $k,
                                  # leaf_reduced => 1,
                                  # series_reduced => 1,
                                 );

    # require Graph::Maker::BinomialTree;
    # my $graph = Graph::Maker->new('binomial_tree',
    #                               order => $k,
    #                               undirected => 1,
    #                              );

    my $diameter = $graph->diameter;
    my $total = Graph_total_path_length($graph);
    my $vertices = $graph->vertices;
    my $average = $total / $diameter / $vertices**2;
    print "$k total=$total diam=$diameter $average\n";
  }
  exit 0;

  sub Graph_total_path_length {
    my ($graph) = @_;
    my $total = 0;
    $graph->for_shortest_paths(sub {
                                 my ($t, $u,$v, $n) = @_;
                                 $total += $t->path_length($u,$v);
                               });
    return $total;
  }
}


{
  #       4   5     3
  #        \ /      |
  # 9---1--11---2--10---0---8       0-10-11-1-9
  #        / \
  #       6   7
  my $edge_aref = [[0,8],[1,9],[0,10],[2,10],[3,10],[1,11],[2,11],[4,11],[5,11],[6,11],[7,11]];
  my $subgraph_edge_aref = [[0,1],[1,2],[2,3],[3,4],[1,5],[2,6]];
  my $ret = edge_aref_is_subgraph($edge_aref, $subgraph_edge_aref);
  print "$ret\n";
  exit 0;
}

{
  # trees

  # require Math::PlanePath::SierpinskiTriangle;
  # my $path = Math::PlanePath::SierpinskiTriangle->new;

  require Math::PlanePath::ToothpickTree;
  my $path = Math::PlanePath::ToothpickTree->new;

  my $depth = 5;
  my $n_lo = $path->n_start;
  my $n_hi = $path->tree_depth_to_n_end($depth);

  require Graph::Easy;
  my $graph = Graph::Easy->new();
  foreach my $n ($n_lo .. $n_hi) {
    foreach my $c ($path->tree_n_children($n)) {
      $graph->add_edge($n,$c);
    }
  }
  print "$graph\n";
  print $graph->as_ascii;
  print $graph->as_graphviz();
  exit 0;
}
{
  # SierpinskiTriangle
  my $depth = 4;

  require Math::PlanePath::SierpinskiTriangle;
  my $path = Math::PlanePath::SierpinskiTriangle->new;
  my $n_lo = $path->n_start;
  my $n_hi = $path->tree_depth_to_n_end($depth);
  my $graph = Graph->new (vertices => [ $n_lo .. $n_hi ],
                          edges => [ map { my $n = $_;
                                           map { [ $n, $_ ] }
                                             $path->tree_n_children($n)
                                           }
                                     $n_lo .. $n_hi ]);
  print "$graph\n";
  ### cyclic: $graph->is_cyclic
  ### acyclic: $graph->is_acyclic
  ### all_successors: $graph->all_successors($n_lo)
  ### neighbours: $graph->neighbours($n_lo)
  ### interior_vertices: $graph->interior_vertices
  ### exterior_vertices: $graph->exterior_vertices

  print "in_degree: ",join(',',map{$graph->in_degree($_)}$n_lo..$n_hi),"\n";
  print "out_degree:   ",join(',',map{$graph->out_degree($_)}$n_lo..$n_hi),"\n";
  print "num_children: ",join(',',map{$path->tree_n_num_children($_)}$n_lo..$n_hi),"\n";
  exit 0;
}
{
  # geng by edge_aref

  # 7 of
  # found:
  #  0-3,1-4,0-5,2-5,0-6,1-6,2-6,4-6,0-7,1-7,3-7,4-7,5-7,0-8,1-8,2-8,4-8,5-8,6-8,7-8 [20 edges]
  # found:
  #  0-3,1-4,0-5,2-5,0-6,1-6,3-6,4-6,1-7,2-7,3-7,4-7,5-7,0-8,1-8,3-8,4-8,5-8,6-8,7-8 [20 edges]
  # found:
  #  0-3,1-4,0-5,2-5,3-5,0-6,1-6,4-6,5-6,1-7,2-7,3-7,4-7,5-7,1-8,2-8,4-8,5-8,6-8,7-8 [20 edges]
  # found:
  #  0-3,0-4,1-4,1-5,2-5,0-6,2-6,3-6,5-6,0-7,2-7,3-7,5-7,6-7,0-8,1-8,2-8,4-8,5-8,6-8 [20 edges]
  # found:
  #  0-3,1-4,2-4,1-5,2-5,0-6,1-6,3-6,0-7,2-7,3-7,4-7,5-7,0-8,1-8,2-8,3-8,4-8,6-8,7-8 [20 edges]
  # found:
  #  0-3,1-4,2-4,1-5,2-5,0-6,1-6,3-6,4-6,0-7,2-7,3-7,5-7,0-8,1-8,2-8,3-8,4-8,6-8,7-8 [20 edges]
  # found:
  #  0-3,0-4,3-4,1-5,2-5,0-6,1-6,3-6,0-7,2-7,3-7,4-7,5-7,0-8,1-8,2-8,4-8,5-8,6-8,7-8 [20 edges]

  my @G;
  my @G_graph;
  require Graph::Maker::Beineke;
  foreach my $N (1 .. 9) {
    my $graph = Graph::Maker->new('beineke', N=>$N, undirected=>1);
    push @G_graph, $graph;
    $G[$N-1] = [ map{[$_->[0]-1, $_->[1]-1]} $graph->edges ];
    my $num_vertices = $graph->vertices;
    my $num_edges    = $graph->edges;
    print "G$N $num_vertices $num_edges\n";
  }

  my $try = sub {
    my ($edge_aref) = @_;
    my @maps;
    foreach my $G (@G) {
      my $map = edge_aref_is_induced_subgraph($edge_aref, $G);
      if (! $map) {
        return;
      }
      push @maps,$map;
    }
    Graph::Graph6::write_graph(str_ref   => \my $g6_str,
                               edge_aref => $edge_aref,
                              );
    $g6_str = graph6_str_to_canonical($g6_str);
    print "found:\n";
    print " ",edge_aref_string($edge_aref),"\n";
    print " $g6_str\n";
    foreach my $map (@maps) {
      print "  $map\n";
    }

    my $graph = Graph->new (undirected => 1);
    foreach my $edge (@$edge_aref) {
      $graph->add_edge(@$edge);
    }
    print "$graph\n";
    foreach my $G (@G_graph) {
      print Graph_is_induced_subgraph($graph, $G),"\n";
    }

    # my $easy = Graph::Easy->new (undirected => 1);
    # foreach my $edge (@$edge_aref) {
    #   $easy->add_edge(@$edge);
    # }
    # print $easy->as_graphviz;
  };

  $try->([ [0,2],[6,5],[0,3],[4,8],[1,2],[4,3],[7,6],[6,1],[7,2],
           [7,1],[4,5],[1,4],[0,8],[2,3],[6,2],[7,5],[1,3],[1,5],
           [0,1],[2,8] ]);
  # 173102:HoCzEt~ in geng -l output

  $| = 1;
  require IPC::Run;
  my @args = ('-c', # connected
              '8',  # vertices
              '13:20');
  IPC::Run::run(['nauty-geng','-u',@args]);
  my $h = IPC::Run::start(['nauty-geng',@args], '>pipe', \*GENG);
  require Graph::Reader::Graph6;
  my $reader = Graph::Reader::Graph6->new;
  my $count = 0;
  my $t = int(time()/10);
  my @edges;
  my $edge_aref = \@edges;
  my $fh = \*GENG;
 GRAPH: while (Graph::Graph6::read_graph(fh => $fh,
                                         edge_aref => $edge_aref)) {
    if (int(time()/10) != $t) {
      print $count,"\n";
      $t = int(time()/10);
    }
    $count++;

    $try->($edge_aref);
    # Graph_view($graph);
  }
  exit 0;
}
{
  # Soltes J2 for Soltes G2 is Beineke G7
  #      a----e
  #     / \   |\
  #    b---c  | g--h
  #     \ /   |/
  #      d----f
  #
  my @graphs;

  my $J2 = Graph->new (undirected => 1);
  $J2->set_graph_attribute (name => "Soltes J2");
  $J2->add_edge('a','b');$J2->add_edge('a','c');$J2->add_edge('a','e');
  $J2->add_edge('b','c');$J2->add_edge('b','d');
  $J2->add_edge('c','d');
  $J2->add_edge('d','f');
  $J2->add_edge('e','f');$J2->add_edge('e','g');
  $J2->add_edge('f','g');
  $J2->add_edge('g','h');
  push @graphs, $J2;

  # Soltes J3 for Soltes G3 = Beineke G2
  #      a---
  #     / \   \
  #    b---c   e
  #     \ / _/ |
  #      d-/---f----g
  # hog not
  #
  my $J3 = Graph->new (undirected => 1);
  $J3->set_graph_attribute (name => "Soltes J3");
  $J3->add_edge('a','b');$J3->add_edge('a','c');$J3->add_edge('a','e');
  $J3->add_edge('b','c');$J3->add_edge('b','d');
  $J3->add_edge('c','d');
  $J3->add_edge('d','e');$J3->add_edge('d','f');
  $J3->add_edge('e','f');
  $J3->add_edge('f','g');
  push @graphs, $J3;

  # Lai and Soltes H4
  # degree=6 claw-free, K5-e free, G5 free, but a non-line
  # has G2 and G8
  my $H4 = Graph_Lai_Soltes_H4();
  push @graphs, $H4;

  my $try = $H4;

  require Graph::Maker::Beineke;
  foreach my $N (1 .. 9) {
    my $G = Graph::Maker->new('beineke', N=>$N, undirected=>1);
    my $bool = Graph_is_induced_subgraph($try, $G);
    print "G$N ", $bool?"yes":"no", "\n";
    push @graphs, $G;
  }
  hog_searches_html(@graphs);
  exit 0;
}

{
  # geng
  require Graph::Maker::Beineke;
  my @G = map {Graph::Maker->new('beineke', N=>$_, undirected=>1)} 1 .. 9;
  foreach my $G (@G) {
    my $num_vertices = $G->vertices;
    my $num_edges    = $G->edges;
    print "$num_vertices $num_edges\n";
  }

  $| = 1;
  require IPC::Run;
  my $h = IPC::Run::start(['nauty-geng',
                           '-c', # connected
                           '9', # vertices
                           '14:20'],
                          '>pipe', \*GENG);
  require Graph::Reader::Graph6;
  my $reader = Graph::Reader::Graph6->new;
  my $count = 0;
  my $t = int(time()/10);
 GRAPH: while (my $graph = $reader->read_graph(\*GENG)) {
    if (int(time()/10) != $t) {
      print $count,"\n";
      $t = int(time()/10);
    }
    $count++;
    foreach my $G (@G) {
      if (! Graph_is_induced_subgraph($graph, $G)) {
        next GRAPH;
      }
    }
    print "$graph\n";
    Graph_view($graph);
  }
  exit 0;
}

{
  # Theorem of the Day line graph, all of Beineke induced sub-graphs

  my $easy = Graph::Easy->new;
  $easy->add_edge('a','b'); $easy->add_edge('a','d'); $easy->add_edge('a','h');
  $easy->add_edge('b','c'); $easy->add_edge('b','d'); $easy->add_edge('b','h');
  $easy->add_edge('c','d'); $easy->add_edge('c','e');
  $easy->add_edge('c','g'); $easy->add_edge('c','h');
  $easy->add_edge('d','e'); $easy->add_edge('d','f'); $easy->add_edge('d','l');
  $easy->add_edge('e','f'); $easy->add_edge('e','l'); $easy->add_edge('e','k');
  $easy->add_edge('e','j'); $easy->add_edge('e','g');
  $easy->add_edge('f','l');
  $easy->add_edge('g','j'); $easy->add_edge('g','k'); $easy->add_edge('g','l');
  $easy->add_edge('g','i'); $easy->add_edge('g','h');
  $easy->add_edge('h','i'); $easy->add_edge('h','l');
  $easy->add_edge('i','l');
  $easy->add_edge('j','k');
  $easy->add_edge('k','l');
  $easy->set_attribute('flow','south');
  $easy->set_attribute('root','a'); # for as_graphviz()
  $easy->{att}->{root} = 'a';       # for root_node() for as_ascii()
  # Graph_Easy_view($easy);

  my $num_vertices = $easy->nodes;
  my $num_edges    = $easy->edges;
  print "num vertices $num_vertices  num edges $num_edges\n";

  my $graph = Graph_theorem_of_the_day();
  my @graphs;
  # 9,20
  foreach my $edge_aref ([ [108,2],[6,5],[108,3],[4,106],[1,2],[4,3],[107,6],[6,1],[107,2],[107,1],[4,5],[1,4],[108,106],[2,3],[6,2],[107,5],[1,3],[1,5],[108,1],[2,106] ],

                         [ [106,3],[108,1],[2,1],[3,4],[108,2],[1,6],[106,2],[1,4],[5,6],[2,107],[2,3],[107,3],[5,4],[2,6],[108,6],[1,5],[106,107],[106,4],[1,107],[1,3] ],

                         [ [1,3],[5,4],[1,5],[108,106],[2,6],[106,4],[1,107],[106,107],[1,6],[1,4],[106,2],[2,107],[5,6],[107,3],[2,3],[106,3],[108,3],[3,4],[108,4],[2,1],
                         ]) {

    $graph = Graph->new (undirected => 1);
    foreach my $edge (@$edge_aref) {
      $graph->add_edge(@$edge);
    }
    # Graph_view($graph);
    push @graphs, $graph;

    require Graph::Maker::Beineke;
    foreach my $N (1 .. 9) {
      my $G = Graph::Maker->new('beineke', N=>$N, undirected=>1);
      my $bool = Graph_is_induced_subgraph($graph, $G);
      print "G$N ", $bool?"yes":"no", "\n";
    }
    print graph6_str_to_canonical(Graph_graph6_str($graph));
  }
  hog_searches_html(@graphs);
  exit 0;
}

{
  # extending from G9

  # [108,2],[6,5],[108,3],[4,106],[1,2],[4,3],[107,6],[6,1],[107,2],[107,1],[4,5],[1,4],[108,106],[2,3],[6,2],[107,5],[1,3],[1,5],[108,1],[2,106],
  #   vertices 9 edges 20

  # [106,3],[108,1],[2,1],[3,4],[108,2],[1,6],[106,2],[1,4],[5,6],[2,107],[2,3],[107,3],[5,4],[2,6],[108,6],[1,5],[106,107],[106,4],[1,107],[1,3],
  #   vertices 9 edges 20

  # [1,3],[5,4],[1,5],[108,106],[2,6],[106,4],[1,107],[106,107],[1,6],[1,4],[106,2],[2,107],[5,6],[107,3],[2,3],[106,3],[108,3],[3,4],[108,4],[2,1],
  #   vertices 9 edges 20


  require Graph::Maker::Beineke;
  my $G9 = Graph::Maker->new('beineke', N=>9, undirected=>1);
  my @G = map {Graph::Maker->new('beineke', N=>$_, undirected=>1)} 1 .. 8;

  my %seen;
  my @pending = ([$G9,0]);
  while (@pending) {
    use sort 'stable';
    my $num_pending = scalar(@pending);
    @pending = sort {$b->[1] <=> $a->[1]} @pending;
    my $c = shift @pending;
    my ($parent,$count) = @$c;

    my @vertices = $parent->vertices;
    @vertices = sort {$a<=>$b} @vertices;
    my $num_vertices = scalar(@vertices);
    print "try $num_vertices($count)  $parent  (pending $num_pending)\n";
    my $new = 100 + $num_vertices;
    $parent->add_vertex($new);
    my $same_count = 0;
    foreach my $i (1 .. 2**scalar(@vertices)-1) {
      my $g = $parent->copy;
      foreach my $bit (0 .. $#vertices) {
        if ($i & (1 << $bit)) {
          $g->add_edge($new, $vertices[$bit]);
        }
      }
      next if scalar($g->edges) > 20;

      if ($seen{graph6_str_to_canonical(Graph_graph6_str($g))}++) {
        $same_count++;
        # printf "  %b skip\n", $i;
        next;
      }

      my $count = 0;
      my @got;
      foreach my $n (0 .. $#G) {
        my $map = Graph_is_induced_subgraph($g, $G[$n]);
        if ($map) {
          push @got, 'G'.($n+1);
          $count++;
          # printf "  %b  G%d %s\n", $i, $n+1, $map;
        } else {
          if ($num_vertices == 8) {  # so $g is 8
            push @got, 'not'.($n+1);
            last;
          }
        }
      }
      # printf "  %b  %s\n", $i, join(',',@got);

      if ($count == 8) {
        print "found $g\n";
        foreach my $e ($g->edges) {
          print "[$e->[0],$e->[1]],"
        }
        print "\n";
        print "  vertices ",scalar($g->vertices)," edges ",scalar($g->edges),"\n";
        Graph_view($g);
        next;
      }
      if ($num_vertices < 8) {  # so $g is 8
        push @pending, [$g, $count];
      }
    }
    print "  skipped $same_count same\n";
  }
  exit 0;
}






{
  # which G1-G9 subgraphs
  {
    # Soltes H1
    #    a---b
    #    | / |
    #    c---d
    #    | / |
    #    e---f
    #     \ /
    #      g
    #
    my $H1 = Graph->new (undirected => 1);
    $H1->add_edge('a','b'); $H1->add_edge('a','c');
    $H1->add_edge('b','c'); $H1->add_edge('b','d');
    $H1->add_edge('c','d'); $H1->add_edge('c','e');
    $H1->add_edge('d','e'); $H1->add_edge('d','f');
    $H1->add_edge('e','f');
    $H1->add_edge('e','g');$H1->add_edge('f','g');
    my @graphs = ($H1);

    # Soltes H2
    #
    require Graph::Maker::Wheel;
    my $H2 = Graph::Maker->new('wheel', N=>6, undirected=>1);
    $H2->set_graph_attribute (name => 'H2');
    $H2->add_edge(2,'a');
    $H2->add_edge(3,'a');
    push @graphs, $H2;

    # Soltes H3
    #
    require Graph::Maker::Wheel;
    my $H3 = Graph::Maker->new('wheel', N=>6, undirected=>1);
    $H3->set_graph_attribute (name => 'H3');
    $H3->add_edge(2,'a'); $H3->add_edge(3,'a');
    $H3->add_edge(3,'b'); $H3->add_edge(4,'b');
    $H3->add_edge('a','b');
    push @graphs, $H3;

    # Soltes J2,J3
    my $J2 = Graph_Soltes_J2();
    my $J3 = Graph_Soltes_J3();
    push @graphs, $J2, $J3;

    my $try = $J3;
    # $try->add_edge('g','1');
    # $try->add_edge('1','2');

    require Graph::Maker::Beineke;
    foreach my $N (1 .. 9) {
      my $G = Graph::Maker->new('beineke', N=>$N, undirected=>1);
      my $bool = Graph_is_induced_subgraph($try, $G);
      print "G$N ", $bool?"yes":"no", "\n";
      push @graphs, $G;
    }
    hog_searches_html(@graphs);
  }
  exit 0;
}

{
  # Beineke

  my @graphs;
  foreach my $N (1 .. 9) {
    require Graph::Maker::Beineke;
    my $graph = Graph::Maker->new('beineke', N=>$N, undirected=>1);
    push @graphs, $graph;
  }
  {
    # Soltes H1
    # G8 a---b
    #    | / |
    #    c---d
    #    | / |
    #    e---f
    #     \ /
    #      g
    # hog not
    #
    my $easy = Graph::Easy->new (undirected => 1);
    $easy->set_attribute (label => 'H1');
    $easy->add_edge('a','b'); $easy->add_edge('a','c');
    $easy->add_edge('b','c'); $easy->add_edge('b','d');
    $easy->add_edge('c','d'); $easy->add_edge('c','e');
    $easy->add_edge('d','e'); $easy->add_edge('d','f');
    $easy->add_edge('e','f');
    $easy->add_edge('e','g');$easy->add_edge('f','g');
    push @graphs, $easy;
  }
  {
    # Soltes H2
    # hog not
    #
    require Graph::Maker::Wheel;
    my $graph = Graph::Maker->new('wheel', N=>6, undirected=>1);
    $graph->set_graph_attribute (name => 'H2');
    $graph->add_edge(2,'a');
    $graph->add_edge(3,'a');
    push @graphs, $graph;
  }
  {
    # Soltes H3
    # hog not
    #
    require Graph::Maker::Wheel;
    my $graph = Graph::Maker->new('wheel', N=>6, undirected=>1);
    $graph->set_graph_attribute (name => 'H3');
    $graph->add_edge(2,'a'); $graph->add_edge(3,'a');
    $graph->add_edge(3,'b'); $graph->add_edge(4,'b');
    $graph->add_edge('a','b');
    push @graphs, $graph;
  }

  {
    # Soltes J1, same as Soltes G1
    #          c
    #         /|\
    #    a---b | e---f
    #         \|/
    #          d
    # https://hog.grinvin.org/ViewGraphInfo.action?id=922
    my $easy = Graph::Easy->new (undirected => 1);
    $easy->set_attribute (label => 'J1');
    $easy->add_edge('a','b');
    $easy->add_edge('b','c'); $easy->add_edge('b','d');
    $easy->add_edge('c','d'); $easy->add_edge('c','e');
    $easy->add_edge('d','e');
    $easy->add_edge('e','f');
    push @graphs, $easy;
  }
  {
    # Soltes J2
    #      a----e
    #     / \   |\
    #    b---c  | g--h
    #     \ /   |/
    #      d----f
    # hog not
    #
    my $easy = Graph::Easy->new (undirected => 1);
    $easy->set_attribute (label => 'J2');
    $easy->add_edge('a','b');$easy->add_edge('a','c');$easy->add_edge('a','e');
    $easy->add_edge('b','c');$easy->add_edge('b','d');
    $easy->add_edge('c','d');
    $easy->add_edge('d','f');
    $easy->add_edge('e','f');$easy->add_edge('e','g');
    $easy->add_edge('f','g');
    $easy->add_edge('g','h');
    push @graphs, $easy;
  }
  {
    # Soltes J3
    #      a---
    #     / \   \
    #    b   c   e
    #     \ / _/ |
    #      d-/---f----g
    # hog not
    #
    my $easy = Graph::Easy->new (undirected => 1);
    $easy->set_attribute (label => 'J3');
    $easy->add_edge('a','b');$easy->add_edge('a','c');$easy->add_edge('a','e');
    $easy->add_edge('b','d');
    $easy->add_edge('c','d');
    $easy->add_edge('d','e');$easy->add_edge('d','f');
    $easy->add_edge('e','f');
    $easy->add_edge('f','g');
    push @graphs, $easy;
  }
  {
    # Soltes J4, same as Soltes G4
    #    a---c
    #    |\ /|\
    #    | . | e---f
    #    |/ \|/
    #    b---d
    # hog not
    #
    my $easy = Graph::Easy->new (undirected => 1);
    $easy->set_attribute (label => 'J4');
    $easy->add_edge('a','b');$easy->add_edge('a','d');$easy->add_edge('a','c');
    $easy->add_edge('b','d');$easy->add_edge('b','c');
    $easy->add_edge('c','d');$easy->add_edge('c','e');
    $easy->add_edge('d','e');
    $easy->add_edge('e','f');
    push @graphs, $easy;
  }
  {
    # Soltes J6 = Claw = Star-4
    # https://hog.grinvin.org/ViewGraphInfo.action?id=500
    require Graph::Maker::Star;
    my $graph = Graph::Maker->new('star', N=>4, undirected=>1);
    $graph->set_graph_attribute (name => 'J6');
    push @graphs, $graph;
  }
  {
    # Lai and Soltes H4
    # [hog recheck]
    my $H4 = Graph_Lai_Soltes_H4();
    push @graphs, $H4;
  }
  hog_searches_html(@graphs);
  exit 0;
}


{
  # K5-e
  require Graph::Maker::Complete;
  require Graph::Maker::Beineke;
  my $K5 = Graph::Maker->new('complete', N => 5, undirected => 1);
  $K5->delete_edge(1,3);
  my $G3 = Graph::Maker->new('beineke', N => 3, undirected => 1);
  Graph_view($K5);
  Graph_view($G3);

  my $iso = Graph_is_isomorphic($K5,$G3);
  print "isomorphic: ",$iso?"yes":"no", "\n";
  exit 0;
}






{
  # Hampton Court
  # https://hog.grinvin.org/ViewGraphInfo.action?id=21084
  # straight-line diagram in W.H.Matthews fig 136

  # file:///usr/share/doc/graphviz/html/info/lang.html

  my $str = <<'HERE';
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X            X     X          X               X
X XXXXXXXXXX X XXXXX @@@@@@@@ X XXXXXXXXXXXXX X
X X          X X            @ X             X X
X X XXXXXXXXXX X XXXXXXXXXX @ XXXXXXXXXXXXX X X
X X X          X    X       @             X X X
X X X XXXXXXXXXXXXX X @@@@@@@@@@@@@ XXXXX X X X
X X X X   X         X             @ X   X X X X
X X   X X X XXXXXXXXXXXXXXXXXXXXX @ X X X X X X
X XXX X X X X...................X @ X X X   X X
X   X X X X X...................X @ X X X XXX X
XXX X X X X X.......G...........X @ X X X X   X
X   X X X X X....... ...........X @ X X X X XXX
X XXX X X X X....... ...........X @ X X X X   X
X X   X X X XXXXXXXX XXXXXXXXXXXX @ X X X X X X
X X X X X X        X X            @ X X   X X X
X X X X X XXXXXXXX X X @@@@@@@@@@@@ X XXXXX X X
X X X   X        X X X                X     X X
X X XXXXXXXXXXXXXX X XXXXXXXXXXXXXXXXXXXXXXXX X
X X                X                          X
X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X                                             X
XXXXXXXXXXXXXXXXXXXXEXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
HERE
  $str =~ s/\n$//;
  my @rows = split /\n/, $str;
  my $width = length($rows[0]);
  my $xy_to_name = sub {
    my ($x,$y) = @_;
    return "p$x,$y";
  };
  my $get = sub {
    my ($x,$y) = @_;
    return substr($rows[$y],$x,1);
  };
  my @dir4_to_dx = (1,0,-1,0);
  my @dir4_to_dy = (0,1,0,-1);

  my $easy = Graph::Easy->new (undirected => 1);
  my ($ex,$ey);
  my ($gx,$gy);
  foreach my $y (0 .. $#rows) {
    foreach my $x (0 .. $width) {
      my $c = $get->($x,$y);
      print $c;
      if ($c eq ' ') {
        $easy->add_vertex($xy_to_name->($x,$y));
        foreach my $dir (0 .. $#dir4_to_dx) {
          my $x2 = $x + $dir4_to_dx[$dir];
          my $y2 = $y + $dir4_to_dy[$dir];
          my $c2 = $get->($x2,$y2);
          next unless $c2 eq ' ';
          $easy->add_edge_once( sort($xy_to_name->($x,$y),
                                     $xy_to_name->($x2,$y2)));
        }
      } elsif ($c eq 'E') {
        ($ex,$ey) = ($x,$y-1);
      } elsif ($c eq 'G') {
        ($gx,$gy) = ($x,$y+1);
      }
    }
    print "\n";
  }

  my $entrance_name = 'Entrance';
  $easy->set_attribute('flow','east');
  $easy->rename_node($easy->node($xy_to_name->($ex,$ey)), $entrance_name);
  $easy->set_attribute('root',$entrance_name); # for as_graphviz()
  $easy->{att}->{root} = $entrance_name;       # for root_node() for as_ascii()
  $easy->node($entrance_name)->set_attribute('x-dot-pos',"0,0!");
  $easy->set_attribute('x-dot-overlap',"false");
  $easy->set_attribute('x-dot-splines',"true");

  $easy->rename_node($easy->node($xy_to_name->($gx,$gy)),"Goal");
  $easy->node("Goal")->set_attribute('x-dot-pos',"8,0!");

  Graph_Easy_branch_reduce($easy);

  my @entrance_edges = $easy->node($entrance_name)->edges;
  my $entrance_degree = scalar(@entrance_edges);
  print "entrance degree $entrance_degree   ",
    Graph_Easy_edge_list_string(@entrance_edges),"\n";

  my $num_nodes = $easy->nodes;
  print "$num_nodes nodes\n";
  print $easy->as_graphviz;
  print $easy->as_graph6;
  print graph6_str_to_canonical($easy->as_graph6);
  Graph_Easy_view($easy);
  hog_searches_html($easy);
  exit 0;

  sub Graph_Easy_branch_reduce {
    my ($easy) = @_;
    my $root = $easy->attribute('root');
    ### $root
    my $more;
    do {
      $more = 0;
      foreach my $v ($easy->vertices) {
        my @edges = $v->edges;
        if ($v->name ne $root && @edges == 2) {
          ### del: "$v"
          my @join = grep {$_ != $v} ($edges[0]->from,
                                      $edges[0]->to,
                                      $edges[1]->from,
                                      $edges[1]->to);
          $easy->del_edge($edges[0]);
          $easy->del_edge($edges[1]);
          $easy->del_node($v);
          $easy->add_edge(@join);
          $more = 1;
        }
      }
    } while ($more);
  }
}





{
  # Graph::Maker::KnightGrid max degree
  my @values;
  foreach my $num_dims (1 .. 6) {
    require Graph::Maker::KnightGrid;
    my $graph = Graph::Maker->new('knight_grid',
                                  dims => [(5)x$num_dims],
                                  undirected => 1,
                                  cyclic => 0,
                                 );
    my $max_degree = max(map {$graph->degree($_)} $graph->vertices);
    my $value = $max_degree / 8;
    print "dims=$num_dims  $max_degree  $value\n";
    push @values, $value;
  }
  require Math::OEIS::Grep;
  Math::OEIS::Grep->search(array => \@values, verbose=>1);
  exit 0;
}

{
  # Graph::Maker::Grid long/short sides numbering

  {
    require Graph::Maker::Grid;
    my $graph = Graph::Maker->new('grid',
                                  dims => [3,4],
                                  undirected => 0,
                                  cyclic => 0,
                                 );
    Graph_view($graph);
  }
  {
    require Graph::Maker::KnightGrid;
    my $graph = Graph::Maker->new('knight_grid',
                                  dims => [3,4],
                                  undirected => 0,
                                  cyclic => 0,
                                 );
    Graph_view($graph);
  }

  my $dims = [3,4];
  foreach my $i (0 .. $dims->[0]-1) {
    foreach my $j (0 .. $dims->[1]-1) {
      print "  ",Graph::Maker::KnightGrid::_coordinates_to_vertex([$i,$j],$dims);
    }
    print "\n";
  }
  exit 0;
}

{
  # 3x3 with wraparound
  #
  # 0 -- 1 -- 2
  # |    |    |
  # 3----4----5
  # |    |    |
  # 6 -- 7 -- 8
  #
  my $edge_aref = [ [0,1],[1,2],[2,0],
                    [3,4],[4,5],[5,3],
                    [6,7],[7,8],[8,6],

                    [0,3],[3,6],[6,0],
                    [1,4],[4,7],[7,1],
                    [2,5],[5,8],[8,2],
                  ];
  my $flat_g6_str;
  Graph::Graph6::write_graph(str_ref => \$flat_g6_str,
                             edge_aref => $edge_aref);
  my $flat_g6_canonical = graph6_str_to_canonical($flat_g6_str);
  print $flat_g6_canonical;

  {
    my $edge_aref = [ [0,4],[4,8],[8,0],
                      [1,5],[5,6],[6,1],
                      [2,3],[3,7],[7,2],

                      [0,5],[5,7],[7,0],
                      [1,3],[3,8],[8,1],
                      [2,4],[4,6],[6,2],
                    ];
    my $cross_g6_str;
    Graph::Graph6::write_graph(str_ref => \$cross_g6_str,
                               edge_aref => $edge_aref);
    my $cross_g6_canonical = graph6_str_to_canonical($cross_g6_str);
    print $cross_g6_canonical;
    $flat_g6_canonical eq $cross_g6_canonical or die;
  }
  {
    # knight
    my $edge_aref = [ [0,7],[7,5],[5,0],
                      [1,8],[8,3],[3,1],
                      [2,6],[6,4],[4,2],

                      [0,8],[8,4],[4,0],
                      [1,6],[6,5],[5,1],
                      [2,7],[7,3],[3,2],
                    ];
    my $cross_g6_str;
    Graph::Graph6::write_graph(str_ref => \$cross_g6_str,
                               edge_aref => $edge_aref);
    my $cross_g6_canonical = graph6_str_to_canonical($cross_g6_str);
    print $cross_g6_canonical;
    $flat_g6_canonical eq $cross_g6_canonical or die;
  }
  {
    # Paley 9
    my $edge_aref = [ [0,1],[1,2],[2,3],
                      [3,4],[4,5],[5,6],
                      [6,7],[7,8],[8,0],

                      [0,2],[0,4],
                      [1,5],[1,6],
                      [2,7],
                      [3,7],[3,5],
                      [4,8],
                      [6,8],
                    ];
    my $cross_g6_str;
    Graph::Graph6::write_graph(str_ref => \$cross_g6_str,
                               edge_aref => $edge_aref);
    my $cross_g6_canonical = graph6_str_to_canonical($cross_g6_str);
    print $cross_g6_canonical;
    $flat_g6_canonical eq $cross_g6_canonical or die;
  }


  {
    require Graph::Maker::Grid;
    my $graph = Graph::Maker->new('grid',
                                  dims => [3,3],
                                  undirected => 1,
                                  cyclic => 1,
                                 );
    my $writer = Graph::Writer::Graph6->new;
    my $g6_str;
    open my $fh, '>', \$g6_str or die;
    $writer->write_graph($graph, $fh);
    my $g6_canonical = graph6_str_to_canonical($g6_str);
    print $g6_canonical;
    $flat_g6_canonical eq $g6_canonical or die;
  }
  {
    require Graph::Maker::KnightGrid;
    my $graph = Graph::Maker->new('knight_grid',
                                  dims => [3,3],
                                  undirected => 1,
                                  cyclic => 1,
                                 );
    my $writer = Graph::Writer::Graph6->new;
    my $g6_str;
    open my $fh, '>', \$g6_str or die;
    $writer->write_graph($graph, $fh);
    my $g6_canonical = graph6_str_to_canonical($g6_str);
    print $g6_canonical;
    $flat_g6_canonical eq $g6_canonical or die;

    my $num_vertices = $graph->vertices;
    my $num_edges    = $graph->edges;
    print "num vertices $num_vertices  num edges $num_edges\n";
  }
  exit 0;
}

{
  # 3x4 knight grid flattened
  #
  # 0 -- 3 -- 6 -- 9       12 nodes, 14 edges
  # |    |    |    |
  # 1    4    7    10
  # |    |    |    |
  # 2 -- 5 -- 8 -- 11
  #
  my $edge_aref = [ [0,1],[1,2],
                    [3,4],[4,5],
                    [6,7],[7,8],
                    [9,10],[10,11],
                    [0,3],[3,6],[6,9],
                    [2,5],[5,8],[8,11],
                  ];
  my $flat_g6_str;
  Graph::Graph6::write_graph(str_ref => \$flat_g6_str,
                             edge_aref => $edge_aref);
  my $flat_g6_canonical = graph6_str_to_canonical($flat_g6_str);
  print $flat_g6_canonical;

  {
    my $edge_aref = [ [0,5],[3,8],[6,11], # vert
                      [3,2],[6,5],[9,8],
                      [0,7],[3,10],[6,1],[9,4],  # horiz
                      [1,8],[4,11],[7,2],[10,5],
                    ];
    my $cross_g6_str;
    Graph::Graph6::write_graph(str_ref => \$cross_g6_str,
                               edge_aref => $edge_aref);
    my $cross_g6_canonical = graph6_str_to_canonical($cross_g6_str);
    print $cross_g6_canonical;
    $flat_g6_canonical eq $cross_g6_canonical or die;
  }

  {
    require Graph::Maker::KnightGrid;
    my $graph = Graph::Maker->new('knight_grid',
                                  dims => [3,4],
                                  undirected => 1,
                                 );
    my $writer = Graph::Writer::Graph6->new;
    my $g6_str;
    open my $fh, '>', \$g6_str or die;
    $writer->write_graph($graph, $fh);
    my $g6_canonical = graph6_str_to_canonical($g6_str);
    print $g6_canonical;
    $flat_g6_canonical eq $g6_canonical or die;

    my $num_vertices = $graph->vertices;
    my $num_edges    = $graph->edges;
    print "num vertices $num_vertices  num edges $num_edges\n";

    hog_searches_html($graph);
  }
  exit 0;
}

{
  # Euler 3x4 knight tour

  my $a = [ [12, 9,  6, 3],
            [ 1, 4, 11, 8],
            [10, 7,  2, 5] ];
  my $reverse = sub {
    my ($a) = @_;
    my $ret = [];
    foreach my $i (0 .. $#$a) {
      foreach my $j (0 .. 3) {
        $ret->[$i]->[$j] = 13 - $a->[$i]->[$j];
      }
    }
    return $ret;
  };
  my $mirror_vertical = sub {
    my ($a) = @_;
    return [ reverse @$a ];
  };
  my $print = sub {
    my ($a) = @_;
    foreach my $i (0 .. $#$a) {
      foreach my $j (0 .. 3) {
        printf "%3d", $a->[$i]->[$j];
      }
      print "\n";
    }
  };
  $print->($a);
  print "transformed\n";
  $a = $reverse->($a);
  $a = $mirror_vertical->($a);
  $print->($a);
  exit 0;
}

{
  # BestOfTree grep

  my @graphs;
  foreach my $k (0 .. 8) {
    require Graph::Maker::BestOfTree;
    my $graph = Graph::Maker->new('best_of_tree',
                                  height => $k,
                                  undirected => 1,
                                 );
    push @graphs, $graph;

    my $num_edges = $graph->edges;
    print "k=$k edges $num_edges\n";

    my $writer = Graph::Writer::Graph6->new;
    my $g6_str;
    open my $fh, '>', \$g6_str or die;
    $writer->write_graph($graph, $fh);
    print graph6_str_to_canonical($g6_str);
  }
  hog_searches_html(@graphs);
  exit 0;
}

{
  # HammingTree grep

  my @graphs;
  foreach my $k (0 .. 8) {
    require Graph::Maker::HammingTree;
    my $graph = Graph::Maker->new('hamming_tree',
                                  level => $k,
                                  undirected => 1,
                                 );
    push @graphs, $graph;

    my $num_edges = $graph->edges;
    print "k=$k edges $num_edges\n";

    my $writer = Graph::Writer::Graph6->new;
    my $g6_str;
    open my $fh, '>', \$g6_str or die;
    $writer->write_graph($graph, $fh);
    print graph6_str_to_canonical($g6_str);
  }
  hog_searches_html(@graphs);
  exit 0;
}

{
  # KnightGrid grep
  # num edges 8*triangular = A033996
  # 3x3 is plain grid torus, Paley on 9 vertices
  #   https://hog.grinvin.org/ViewGraphInfo.action?id=6607
  # 4x4 is tesseract https://hog.grinvin.org/ViewGraphInfo.action?id=1340
  # 5x5 canonical X~}CKMFPACgJONHCAaGW...
  #               X~}CKMFPACgJONHCAaGWbGaO`DH@EWcPOIGXCPHO`DE`GaeAGcj

  # 2x2 torus  *--*
  #            |  |
  #            *--*
  # torus:
  # k=1 edges 1
  # @
  # k=2 edges 4
  # Cr
  # k=3 edges 18
  # H{dQXgj
  # k=4 edges 32
  # Os_????@zKIgIgLGHW?r?
  # k=5 edges 100
  # X~}CKMFPACgJONHCAaGWbGaO`DH@EWcPOIGXCPHO`DE`GaeAGcj

  my @graphs;
  my @values;
  foreach my $size (0 .. 8) {
    require Graph::Maker::KnightGrid;
    my $graph = Graph::Maker->new('knight_grid',
                                  dims => [$size,$size],
                                  undirected => 1,
                                  cyclic => 1,
                                 );
    push @graphs, $graph;

    my $num_edges = $graph->edges;

    print "k=$size edges $num_edges\n";
    push @values, $num_edges;

    my $writer = Graph::Writer::Graph6->new;
    my $g6_str;
    open my $fh, '>', \$g6_str or die;
    $writer->write_graph($graph, $fh);
    print graph6_str_to_canonical($g6_str);
  }
  require Math::OEIS::Grep;
  Math::OEIS::Grep->search(array => \@values, verbose=>1);
  hog_searches_html(@graphs);
  exit 0;
}

{
  # Torus
  # 3x3 Paley https://hog.grinvin.org/ViewGraphInfo.action?id=6607
  # 4x4 tesseract https://hog.grinvin.org/ViewGraphInfo.action?id=1340
  # 5x5,6x6 not
  # k=1 edges 1
  # @
  # k=2 edges 4
  # Cr
  # k=3 edges 18
  # H{dQXgj
  # k=4 edges 32
  # Os_????@zKIgIgLGHW?r?
  # k=5 edges 50
  #     Xs_??KE@?A__?H?O?O?@@?_O_OQ?I?OCSOGcWD??o@OD?Q?SAO?
  # 5x5 Xs_??KE@?A__?H?O?O?@@?_O_OQ?I?OCSOGcWD??o@OD?Q?SAO?

  my @graphs;
  my @values;
  foreach my $size (1 .. 8) {

    require Graph::Maker::Grid;
    my $graph = Graph::Maker->new('grid',
                                  dims => [$size,$size],
                                  undirected => 1,
                                  cyclic => 1,
                                 );
    push @graphs, $graph;

    my $num_edges = $graph->edges;

    print "k=$size edges $num_edges\n";
    push @values, $num_edges;

    my $writer = Graph::Writer::Graph6->new;
    my $g6_str;
    open my $fh, '>', \$g6_str or die;
    $writer->write_graph($graph, $fh);
    print graph6_str_to_canonical($g6_str);

    # my $easy = Graph::Easy->new (undirected => 1);
    # my $connect = sub {
    #   my ($x1,$y1, $x2,$y2) = @_;
    #   $x1 %= $size;
    #   $y1 %= $size;
    #   $x2 %= $size;
    #   $y2 %= $size;
    #   if ($x1 >= 0 && $x1 < $size
    #       && $y1 >= 0 && $y1 < $size
    #       && $x2 >= 0 && $x2 < $size
    #       && $y2 >= 0 && $y2 < $size) {
    #     my $from = "$x1,$y1";
    #     my $to   = "$x2,$y2";
    #     unless ($easy->has_edge($from,$to) || $easy->has_edge($to,$from)) {
    #       $easy->add_edge($from,$to);
    #     }
    #   }
    # };
    # foreach my $x (0 .. $size-1) {
    #   foreach my $y (0 .. $size-1) {
    #     $connect->($x,$y, $x+1, $y);
    #     $connect->($x,$y, $x-1, $y);
    #     $connect->($x,$y, $x, $y+1);
    #     $connect->($x,$y, $x, $y-1);
    #   }
    # }
    # $easy->set_attribute('x-dot-splines',"true");
    # # Graph_Easy_view($easy);
    # push @graphs, $easy;
    #
    # print "k=$size\n";
    # my $g6_str = $easy->as_graph6;
    # print graph6_str_to_canonical($g6_str);
  }
  hog_searches_html(@graphs);
  exit 0;
}
{
  # KnightGrid
  my $size = 4;
  require Graph::Maker::KnightGrid;
  my $graph = Graph::Maker->new('knight_grid',
                                dims => [$size,$size],
                                undirected => 1,
                               );
  # Graph_view($graph);

  require Graph::Convert;
  my $easy = Graph::Convert->as_graph_easy($graph);
  $easy->set_attribute('x-dot-overlap',"false");
  $easy->set_attribute('x-dot-splines',"true");

  require Math::PlanePath::Base::Digits;
  foreach my $node ($easy->nodes) {
    my $name = $node->label;
    my ($x,$y) = Math::PlanePath::Base::Digits::digit_split_lowtohigh($name-1,$size);
    $x += 0;
    $y += 0;
    $node->set_attribute('x-dot-pos', "$x,$y!");
    $node->set_attribute(label => "$x,$y");
  }
  Graph_Easy_view($easy);
  exit 0;
}

{
  # Knight connections
  my $size = 4;
  my $easy = Graph::Easy->new (undirected => 1);
  my $connect = sub {
    my ($x1,$y1, $x2,$y2) = @_;
    if ($x1 >= 1 && $x1 <= $size
        && $y1 >= 1 && $y1 <= $size
        && $x2 >= 1 && $x2 <= $size
        && $y2 >= 1 && $y2 <= $size) {
      my $from = "$x1,$y1";
      my $to   = "$x2,$y2";
      unless ($easy->has_edge($from,$to) || $easy->has_edge($to,$from)) {
        $easy->add_edge($from,$to);
      }
    }
  };
  foreach my $x (1 .. $size) {
    foreach my $y (1 .. $size) {
      foreach my $xsign (1,-1) {
        foreach my $ysign (1,-1) {
          $connect->($x,$y, $x+1*$xsign, $y+2*$ysign);
          $connect->($x,$y, $x+2*$xsign, $y+1*$ysign);
        }
      }
    }
  }
  Graph_Easy_view($easy);
  exit 0;
}


{
  # complete binary tree layout

  # diamond         * H=2            *     H=3               *      H=4
  #                 | 5 points     * * *   13 points       * * *    25
  #             *---*---*        * * * * *               * * * * *
  #                 |              * * *               * * * * * * *
  #                 *                *                   * * * * *
  #                                                        * * *
  #                                                          *
  # p(H) = 4*H*(H-1)/2+1; \\ points reachable
  # v(H) = 2^H-1;         \\ vertices to be drawn
  # d(H) = p(H) - v(H);
  # vector(8,H,p(H))
  # vector(8,H,v(H))
  # vector(8,H,d(H))
  # at H=6
  # p(6) == 61
  # v(6) == 63  \\ too many, so H=5 biggest with layout
  #
  # ternary
  # v(H) = sum(i=0,H-1,3^i);      \\  to be drawn
  # at H=3
  # p(3) == 13
  # v(3) == 13  \\ but not layout, so H=2 biggest ternary with layout
  #
  # A001699 = 1, 1, 3, 21 offset 0
  # a(2) is 3 trees of height 2 being 2 levels including the root
  # A000235 = 0, 0, 0, 1 offset 1
  # a(4)=1 is 1 height 3 tree of 4 nodes  similar A000299

  require Graph::Maker::BalancedTree;
  my @values;
  my $row_start = 0;
  my $row_end = 0;
  my $upto = 1;
  my @edges;
  my $edge_aref = \@edges;
  foreach my $height (2 .. 2) {
    print "height=$height\n";
    foreach my $v ($row_start .. $row_end) {
      push @edges, [$v,$upto++];
      push @edges, [$v,$upto++];
      push @edges, [$v,$upto++]; # ternary
    }
    $row_start = $row_end+1;
    $row_end = $upto-1;
    my $parent_aref = edge_aref_to_parent_aref($edge_aref);
    my $layout = grid_layout($parent_aref);
    if ($layout) {
      grid_layout_check ($edge_aref, $parent_aref, $layout);
      print "  has layout\n";
      foreach my $i (0 .. $upto-1) {
        print "  $i  ",join(',',@{$layout->[$i]}),"\n";
      }
    } else {
      print "  no layout\n";
    }
  }
  exit 0;
}
{
  # count trees no square grid layout
  # A000055 trees n nodes
  # A144520 trees n nodes degree <= n-2, so skip star-n A000055-1
  # A144527 trees n nodes degree <= n-3,  A000055-2
  # not     trees n nodes degree <= n-4
  # A000602 trees n nodes degree 1,4  2     5     8    11    14    17    20
  #                       sans zeros  1,0,0,1,0,0,1,0,0,1,0,0,2,0,0,3,0,0,5
  # A000672 trees degree 1,2,3
  # not     trees degree 1,2,4
  #         trees degree 1,2,3,4 not square grid n=12  1,4,14,43,136
  #         trees degree 1,2,  4 not square grid n=14  1,2,5,13,30,69,162
  #         trees degree 1,    4 not square grid n=14 1of2  n=17 2of3
  # 1,2,3 always square grid?

  # 1,2,3,4 is 12 with 1,3,4
  # 1,2,4   is 14 with 1,4
  # for exactly 1,2,3,4 add to one of the two leaf types in 1,3,4
  # for exactly 1,2,4 add to one of the two leaf types in 1,4

  # trees degree <=6 on triangular grid
  # n=11 first 1,3,8,27,79,232

  my $grid = '6';
  my @values;
  my @graphs;
  my $seen_graphs;
  foreach my $num_vertices (1..20) {
    my $degree_list = [
                       # 1,4,
                       1,2,3,4,5,6
                      ];
    my $iterator_func = make_tree_iterator_edge_aref
      (num_vertices => $num_vertices,
       # degree_max => $num_vertices-4,
       degree_max => $grid,
       # degree_list => $degree_list,
      );
    my $name = "tree $num_vertices degrees ".join(',',@$degree_list);
    my $count = 0;
    my $count_total = 0;
  GRAPH: while (my $edge_aref = $iterator_func->()) {
      $count_total++;
      my $parent_aref = edge_aref_to_parent_aref($edge_aref);

      # restricting to exactly certain set of degrees ...
      # my @actual_degrees = MyGraphs::edge_aref_degrees($edge_aref);
      # join('',@actual_degrees) eq '1234' or next;

      my $layout = grid_layout($parent_aref, grid => $grid);
      if ($layout) {
        # grid_layout_check ($edge_aref, $parent_aref, $layout);
        next;
      } else {
        # print "Cannot layout\n";
      }

      if (! $seen_graphs) {
        $name .= " (actual "
          . join(',',MyGraphs::edge_aref_degrees($edge_aref))
          . ")";
        my $easy = MyGraphs::Graph_Easy_from_edge_aref($edge_aref);
        $easy->set_attribute(label => $name);
        push @graphs, $easy;
        my $g6_str = $easy->as_graph6;
        print MyGraphs::edge_aref_string($edge_aref),"\n";
        MyGraphs::Graph_Easy_print_adjacency_matrix($easy);
        print $g6_str;
        print graph6_str_to_canonical($g6_str);
      }
      $count++;
    }
    push @values, $count;
    print "n=$num_vertices  $count (out of $count_total)\n";

    if (@graphs && ! $seen_graphs) {
      hog_searches_html(@graphs);
    }
    $seen_graphs ||= @graphs;
  }
  # require Math::OEIS::Grep;
  # Math::OEIS::Grep->search(array => \@values, verbose=>1);
  exit 0;
}

{
  # 12 vertices no square grid layout
  # https://hog.grinvin.org/ViewGraphInfo.action?id=604
  # is K???????{XMC
  # but picture K?????H@b_OF

  my $orig_g6_str;
  my %seen;
  my $try_tree = sub {
    my ($parent_aref, $edge_aref) = @_;
    # print "$num_vertices vertices   p=",@$parent[1 .. $num_vertices-1],
    #   " nc=",@num_children[0 .. $num_vertices-1],"\n";

    my $num_vertices = scalar(@$parent_aref);
    my $layout = grid_layout($parent_aref);
    if ($layout) {
      grid_layout_check ($edge_aref, $parent_aref, $layout);
    } else {
      print "Cannot layout\n";
    }
    if ($num_vertices < 5 && $layout) {
      print "can layout\n";
    }
    my $easy = parent_aref_to_Graph_Easy($parent_aref);
    my $g6_str = $easy->as_graph6;

    my $canonical = graph6_str_to_canonical($g6_str);
    # if ($seen{$canonical}++) {
    #   print "duplicate $canonical\n";
    #   return;
    # }
    # print "new $canonical\n";

    if ($num_vertices <= 0 || ! $layout) {
      $easy->layout(timeout => 999);
      print "num_vertices $num_vertices\n";
      print $easy->as_ascii,"\n";
    }

    if (! $layout) {
      {
        print "original\n";
        print $orig_g6_str;
        Graph::Graph6::read_graph(str => $orig_g6_str,
                                  edge_func => sub { print "  ",join('-', @_) });
        print "\n";
        print "\n";

        print "easy $easy  ",($easy->is_directed ? 'directed' : 'undirected'), "\n";
        print " ", Graph_Easy_edges_string($easy),"\n";
        Graph_Easy_print_adjacency_matrix($easy);

        print "via parent_aref\n";
        print $g6_str;
        Graph::Graph6::read_graph(str => $g6_str,
                                  edge_func => sub { print "  ",join('-', @_) });
        print "\n";
        print "  parents  ", join(' ', map {defined $_ ? $_ : 'undef'} @$parent_aref), "\n";
        print "\n";

        print "canonical\n";
        print $canonical;
        Graph::Graph6::read_graph(str => $canonical,
                                  edge_func => sub { print "  ",join('-', @_) });
        print "\n";
        print graph6_str_to_canonical($orig_g6_str);
        print "\n";

        open my $fh, '>', '/tmp/1.g6' or die;
        print $fh $g6_str or die;
        close $fh or die;
      }
      my $graphviz_str = $easy->as_graphviz;
      require File::Slurp;
      File::Slurp::write_file('/tmp/cannot.dot', $graphviz_str) or die;

      IPC::Run::run(['dot', '-Tpng', '/tmp/cannot.dot', '-o', '/tmp/1.png']);
      if ($ENV{'DISPLAY'}) {
        IPC::Run::run(['xdot', '/tmp/cannot.dot']);
      }
    }
  };

  {
    my $iterator_func = make_tree_iterator_edge_aref(num_vertices_min => 12,
                                                     num_vertices_max => 12,
                                                     degree_max => 4);
    my $count = 0;
    while (my $edge_aref = $iterator_func->()) {
      $count++;
      Graph::Graph6::write_graph(str_ref => \$orig_g6_str,
                                 edge_aref => $edge_aref);
      my $parent_aref = edge_aref_to_parent_aref($edge_aref);
      $try_tree->($parent_aref, $edge_aref);
    }
    print "count $count trees\n";
    exit 0;
  }

  {
    $orig_g6_str = 'K??????wCwO['."\n";
    my @edges;
    Graph::Graph6::read_graph(str => $orig_g6_str,
                              edge_aref => \@edges);
    my @parent = (undef, 0,0,0,0, 1,1,1, 2,2,2, 3,3,3, 4);
    @parent = (undef, 0,0,0, 1,1,1, 2,2,2, 3,3);
    $try_tree->(\@parent, \@edges);
    exit 0;
  }

  exit 0;
}

{
  # FibonacciTree series_reduced diameter and centre
  # centre 1,2     for height>=3
  # diameter 2*H-3 for height >=3
  require Graph::Maker::FibonacciTree;
  my @values;
  foreach my $height (1 .. 10) {
    my $graph = Graph::Maker->new('fibonacci_tree',
                                  height => $height,
                                  series_reduced => 1,
                                  undirected => 1,
                                 );
    my $diameter = $graph->diameter;
    print "h=$height centre ",join(',',$graph->centre_vertices),
      "  diameter=$diameter \n";;
  }
  exit 0;
}

{
  # Tesseract cospectral Hoffman
  {
    require Graph::Maker::Hypercube;
    my $graph = Graph::Maker->new('hypercube', N => 4, undirected=>1);
    require Graph::Writer::Matrix;
    print "factor(charpoly(";
    my $writer = Graph::Writer::Matrix->new (format => 'pari');
    $writer->write_graph($graph, \*STDOUT);
    print "))\n";
  }
  {
    require Graph::Reader::Graph6;
    my $reader = Graph::Reader::Graph6->new;
    my $graph = $reader->read_graph('/so/hog/graphs/graph_1167.g6');
    require Graph::Writer::Matrix;
    print "factor(charpoly(";
    my $writer = Graph::Writer::Matrix->new (format => 'pari');
    $writer->write_graph($graph, \*STDOUT);
    print "))\n";
  }
  exit 0;
}





{
  # Konigsberg bridges, edges between bridges
  #
  #                                  0              2
  #     ---0---1-----2---                  1
  #               |
  #               3                          3
  #               |
  #     ---4---5-----6---                  5
  #                                  4              6
  #
  # plain underlying https://hog.grinvin.org/ViewGraphInfo.action?id=28
  # bridge links not
  #
  my $filename = '/tmp/2.g6';
  my $edge_aref = [ [0,1],[0,2],  [0,3], [0,4],[0,5],
                    [1,2],[1,3], [1,4],[1,5],
                    [2,3],[2,6],
                    [3,4],[3,5],[3,6],
                    [4,5],[4,6],
                    [5,6] ];
  Graph::Graph6::write_graph(filename => $filename,
                             edge_aref => $edge_aref)
      or die $!;
  my $parser = Graph::Easy::Parser::Graph6->new;
  my $easy = $parser->from_file($filename);


  $easy = Graph::Easy->new;
  $easy->add_edge('A','C', '0');
  $easy->add_edge('A','C', '1');
  $easy->add_edge('C','D', '2');
  $easy->add_edge('A','D', '3');
  $easy->add_edge('A','B', '4');
  $easy->add_edge('A','B', '5');
  $easy->add_edge('B','D', '6');
  my $g6_land_str = $easy->as_graph6;
  print $easy->as_ascii;


  my $dual = MyGraphs::Graph_Easy_line_graph($easy);

  Graph::Graph6::write_graph(str_ref => \my $g6_str,
                             edge_aref => $edge_aref)
      or die $!;
  my $dual_g6 = $dual->as_graph6;
  print $g6_str;
  print $dual_g6;
  print graph6_str_to_canonical($g6_str);
  print graph6_str_to_canonical($dual_g6);

  hog_searches_html($easy, $dual);

  exit 0;

  sub Graph_Easy_Edge_name {
    my ($edge) = @_;
    return $edge->from->name . $edge->to->name;
  }
}

{
  # Konigsberg, bridges and land
  #
  #             C
  #
  #     ---g----f-----e---
  #                |
  #          A     d     D
  #                |
  #     ---a----b-----c---
  #
  #             B
  #

  {
    my $filename = '/tmp/2.g6';
    my $a = 0;
    my $b = 1;
    my $c = 2;
    my $d = 3;
    my $e = 4;
    my $f = 5;
    my $g = 6;
    my $A = 7;
    my $B = 8;
    my $C = 9;
    my $D = 10;
    my $edge_aref = [ [$C,$g],[$C,$f],[$C,$e],
                      [$A,$a],[$A,$b],[$A,$d],[$A,$f],[$A,$g],
                      [$D,$c],[$D,$d],[$D,$e],
                      [$B,$a],[$B,$b],[$B,$c] ];
    Graph::Graph6::write_graph(filename => $filename,
                               edge_aref => $edge_aref)
        or die $!;
    my $parser = Graph::Easy::Parser::Graph6->new;
    my $easy = $parser->from_file($filename);
    my $g6_str = $easy->as_graph6;
    print $g6_str;
    print graph6_str_to_canonical($g6_str);

    $easy->set_attribute('root','07'); # for as_graphviz()
    $easy->{att}->{root} = '07';       # for root_node() for as_ascii()
    $easy->set_attribute('flow','south');
    hog_searches_html($easy);
    exit 0;
  }
  {
    my $filename = '/tmp/2.g6';
    my $easy = Graph::Easy->new;
    $easy->add_vertices('a','b','c','d','e','f','g');
    foreach my $elem (
                      ['g','C'],['f','C'],['e','C'],
                      ['a','B'],['b','B'],['c','B'],
                      ['A','a'],['A','b'],['A','d'],['A','f'],['A','g'],
                      ['D','c'],['D','d'],['D','e'],

                      # # pasted, typo first f is b
                      # ['A','a'], ['A','b'], ['A','d'], ['A','f'], ['A','g'],
                      # ['D','c'], ['D','d'], ['D','e'],
                      # ['a','B'], ['b','B'], ['c','B'],
                      # ['e','C'], ['f','C'], ['g','C'],

                     ) {
      $easy->add_edge(reverse @$elem);
    }
    my $g6_str = $easy->as_graph6;
    $easy->set_attribute('root','A'); # for as_graphviz()
    $easy->{att}->{root} = 'A';       # for root_node() for as_ascii()
    $easy->set_attribute('flow','south');
    my $graphviz_str = $easy->as_graphviz;

    print $g6_str;
    print graph6_str_to_canonical($g6_str);

    MyGraphs::hog_searches_html($easy);

    exit 0;
  }
}
{
  # Konigsberg, vertex for each side of each bridge
  #
  #                                               1
  #        0    1     2                        0-----2
  #     ---g----f-----e---
  #        3    4  |  5                         3--4         5
  #               6d7                                5     7 |
  #        8    9  |  10                        8--9         3
  #     ---a----b-----c---
  #       11   12     13                       11----13
  #                                               12

  my $filename = '/tmp/2.g6';
  my $easy = Graph::Easy->new;
  foreach my $elem (
                    [0,3],[1,4],[2,5],
                    [0,1],[0,2],[1,2], # clique

                    [8,11],[9,12],[10,13], [6,7],

                    [3,4],[3,6],[3,8],[3,9],  # clique
                    [4,6],[4,8],[4,9],
                    [6,8],[6,9],
                    [8,9],

                    [5,7],[5,10],[7,10], # clique
                    [11,12],[11,13],[12,13], # clique
                   ) {
    $easy->add_edge(@$elem);
  }

  $easy->set_attribute('root','1'); # for as_graphviz()
  $easy->{att}->{root} = '1';       # for root_node() for as_ascii()
  $easy->set_attribute('flow','south');
  hog_searches_html($easy);
  exit 0;
}

{
  # Konigsberg bridges, edges between unconnected bridges
  #
  #                                  0              2
  #     ---0---1-----2---                  1
  #               |
  #               3                          3
  #               |
  #     ---4---5-----6---                  5
  #                                  4              6
  #
  my $edge_aref = [ [0,1],[0,2],  [0,3], [0,4],[0,5],
                    [1,2],[1,3], [1,4],[1,5],
                    [2,3],[2,6],
                    [3,4],[3,5],[3,6],
                    [4,5],[4,6],
                    [5,6] ];
  my $graph = Graph->new (undirected => 1);
  foreach my $edge (@$edge_aref) {
    $graph->add_edge(@$edge);
  }

  print scalar($graph->edges)," edges\n";
  $graph = $graph->complement;
  Graph_view($graph);
  print "complement ",scalar($graph->edges)," edges\n";
  exit 0;
}








{
  # trees no layout on square grid
  #
  # 3,3,3,0 https://hog.grinvin.org/ViewGraphInfo.action?id=582
  # 3,3,2,1 not
  # 3,2,2,2 not
  my $n = 1;
  foreach my $list ([3, 3, 3, 0],
                    [3, 3, 2, 1],
                    [3, 2, 2, 2]) {
    $list->[0]+$list->[1]+$list->[2]+$list->[3] == 9 or die;
    print @$list,"  n=$n\n";

    my $graph = Graph->new (undirected => 1);
    $graph->add_vertex(0);
    $graph->add_edge(0,1);
    $graph->add_edge(0,2);
    $graph->add_edge(0,3);
    $graph->add_edge(0,4);
    my $v = 5;
    foreach my $i (0 .. $#$list) {
      my $from = $i+1;
      foreach (1 .. $list->[$i]) {
        $graph->add_edge($from, $v++);
      }
    }
    my $writer = Graph::Writer::Graph6->new;
    $writer->write_graph($graph, "/tmp/$n.g6");

    print "  centre: ",join(' ',$graph->centre_vertices),"\n";

    {
      require Graph::Convert;
      my $easy = Graph::Convert->as_graph_easy($graph);
      my $graphviz_str = $easy->as_graphviz;
      # print $graphviz_str;
      my $png_filename = "/tmp/$n.png";
      require IPC::Run;
      IPC::Run::run(['dot','-Tpng'], '<',\$graphviz_str, '>',$png_filename);
      # print $easy->as_ascii;
    }

    $n++;
  }
  exit 0;
}

#------------------------------------------------------------------------------

BEGIN {
  my @dir4_to_dx = (1,0,-1,0);
  my @dir4_to_dy = (0,1,0,-1);

  my @dir6_to_dx = (2, 1,-1,-2, -1, 1);
  my @dir6_to_dy = (0, 1, 1, 0, -1,-1);

  sub grid_layout {
    my ($parent_aref, %options) = @_;
    ### grid_layout() ...

    my $grid = $options{'grid'} || '4';
    my $dir_to_dx;
    my $dir_to_dy;
    if ($grid eq '6') {
      $dir_to_dx = \@dir6_to_dx;
      $dir_to_dy = \@dir6_to_dy;
    } else {
      $dir_to_dx = \@dir4_to_dx;
      $dir_to_dy = \@dir4_to_dy;
    }

    my $num_vertices = scalar(@$parent_aref);
    my $origin = $#$parent_aref + 5;
    my @layout = ([$origin, $origin]);  # v=0
    my @occupied;

    $occupied[$origin][$origin] = 0;
    my @directions = (3, -1);   # direction of $v from its parent

    my $v = 1;
    for (;;) {
      my $dir = ++$directions[$v];
      ### at: "$v consider direction $dir  parent $parent_aref->[$v]"
      if ($dir > $#$dir_to_dx) {
        ### backtrack ...
        $v--;
        if ($v < 1) {
          return undef;
        }
        # unplace $v
        my ($x,$y) = @{$layout[$v]};
        undef $occupied[$x][$y];
        next;
      }

      my ($x,$y) = @{$layout[$parent_aref->[$v]]};
      $x += $dir_to_dx->[$dir];
      $y += $dir_to_dy->[$dir];
      if (defined $occupied[$x][$y]) {
        next;
      }

      # place and go to next vertex
      $occupied[$x][$y] = $v;
      @{$layout[$v]} = ($x, $y);
      $v++;
      if ($v >= $num_vertices) {
        ### successful layout ...
        ### @layout
        return \@layout;
      }
      $directions[$v] = -1;
    }
  }
}

sub grid_layout_check {
  my ($edge_aref, $parent_aref, $layout_aref) = @_;
  # my $num_vertices = edge_aref_num_vertices($edge_aref);
  my $bad;
  foreach my $edge (@$edge_aref) {
    my ($from, $to) = @$edge;
    if (! defined $layout_aref->[$from]) {
      $bad = "missing layout for vertex $from";
      last;
    }
    if (! defined $layout_aref->[$to]) {
      $bad = "missing layout for vertex $to";
      last;
    }

    my ($x_from,$y_from) = @{$layout_aref->[$from]};
    my ($x_to,$y_to)     = @{$layout_aref->[$to]};
    if ($x_from < 0 || $y_from < 0) {
      $bad = "negative coordinate at $from";
      last;
    }
    if ($x_to < 0 || $y_to < 0) {
      $bad = "negative coordinates at $to";
      last;
    }
    if (abs($x_from - $x_to) + abs($y_from - $y_to) != 1) {   # dx+dy
      $bad = "layout not a unit step $from to $to";
      last;
    }
  }
  if ($bad) {
    print "layout length ", scalar(@$layout_aref),"\n";
    foreach my $v (0 .. $#$layout_aref) {
      print "$v at ",join(', ', @{$layout_aref->[$v]}),"\n";
    }
    print "edges";
    foreach my $edge (@$edge_aref) {
      print "  ",join('-', @$edge);
    }
    print "\n";
    print "parents  ", join(' ', map {defined $_ ? $_ : 'undef'} @$parent_aref), "\n";
    die $bad
  }
}
sub edge_aref_num_vertices {
  my ($edge_aref) = @_;
  if (! @$edge_aref) { return 0; }
  return max(map {@$_} @$edge_aref) + 1;
}

sub parent_aref_to_Graph_Easy {
  my ($parent_aref) = @_;
  my $graph = Graph::Easy->new(undirected => 1);
  if (@$parent_aref) {
    $graph->add_vertex(0);
    foreach my $v (1 .. $#$parent_aref) {
      $graph->add_edge($v,$parent_aref->[$v]);
    }
  }
  return $graph;
}

sub edge_aref_to_parent_aref {
  my ($edge_aref) = @_;
  ### edge_aref_to_parent_aref() ...

  my @neighbours;
  foreach my $edge (@$edge_aref) {
    my ($from, $to) = @$edge;
    push @{$neighbours[$from]}, $to;
    push @{$neighbours[$to]}, $from;
  }

  my @parent;
  my @n_to_v = (0);
  my @v_to_n = (0);
  my $upto_v = 1;
  for (my $v = 0; $v < $upto_v; $v++) {
    ### neighbours: "$v=n$v_to_n[$v] to n=".join(',',@{$neighbours[$v_to_n[$v]]})
    foreach my $n (@{$neighbours[$v_to_n[$v]]}) {
      if (! defined $n_to_v[$n]) {
        $n_to_v[$n] = $upto_v;
        $v_to_n[$upto_v] = $n;
        $parent[$upto_v] = $v;
        $upto_v++;
      }
    }
  }
  foreach my $edge (@$edge_aref) {
    foreach my $n (@$edge) {
      $n = $n_to_v[$n]; # mutate array
    }
  }

  ### @parent
  ### num_vertices: scalar(@parent)
  return \@parent;
}
sub parent_aref_to_edge_aref {
  my ($parent_aref) = @_;
  return [ map {[$parent_aref->[$_] => $_]} 1 .. $#$parent_aref ];
}

# Trees by search.
# {
#   my @parent = (undef, -1);
#   my $v = 1;
#   for (;;) {
#     my $p = ++$parent[$v];
#     ### at: "$v consider new parent $p"
#     if ($p >= $v) {
#       ### backtrack ...
#       $v--;
#       if ($v < 1) { last; }
#       $p = $parent[$v];  # unparent this preceding v
#       $num_children[$p]--;
#       next;
#     }
#
#     if ($num_children[$p] >= ($p==0 ? 4 : 3)) {
#       next;
#     }
#
#     $num_vertices = $v;
#     $process_tree->();
#
#     if ($v < $num_vertices_limit) {
#       # descend
#       $num_children[$p]++;
#       # $num_children[$p] == grep {$_==$p} @parent[1..$v] or die;
#       $num_children[$v] = 0;
#       $v++;
#       $parent[$v] = -1;
#       $num_vertices = $v;
#     }
#   }
# }

# Tree iterator by parent.
# {
#   @parent = (undef);
#   @num_children = (0);
#   my $v = 0;
#   for (;;) {
#     $num_children[$v]++;
#     my $new_v = $v + $num_children[$v];
#     ### at: "$v consider new children $num_children[$v]"
#
#     if ($num_children[$v] > ($v==0 ? 4 : 3)
#         || $new_v > $num_vertices_limit) {
#       ### backtrack ...
#       $v = $parent[$v] // last;
#       next;
#     }
#
#     # add children
#     foreach my $i (1 .. $num_children[$v]) {
#       my $c = $v + $i;
#       $parent[$c] = $v;
#       $num_children[$c] = 0;
#     }
#     $v = $new_v-1;
#     $num_vertices = $v;
#     $process_tree->();
#   }
# }


sub Graph_Easy_print_adjacency_matrix {
  my ($easy) = @_;
  my $has_edge_either = ($easy->is_directed
                         ? \&Graph::Easy::As_graph6::_has_edge_either_directed
                         : 'has_edge');
  my @vertices = $easy->sorted_nodes('name');
  foreach my $from (0 .. $#vertices) {
    foreach my $to (0 .. $#vertices) {
      print $easy->$has_edge_either($vertices[$from], $vertices[$to]) ? ' 1' : ' 0';
    }
    print "\n";
  }
}

{
  # LWP post

  require HTTP::Request::Common;
  my $hog_url = 'http://hog.grinvin.org';
  my $graph6_str = 'Bw'; # complete 3

  require LWP::UserAgent;
  my $ua = LWP::UserAgent->new (ssl_opts => { verify_hostname => 0 });
  $ua->ssl_opts(verify_hostname => 0);

  # must have file=something and Content-Type or else error
  # upload => $graph6_str,
  my $req = HTTP::Request::Common::POST
    ("$hog_url/DoSearchGraphFromFile.action",
     Content_Type => 'form-data',
     Content => [graphFormatName => "Graph6",
                 upload => [undef, "foo.g6",
                            Content_Type => 'text/plain',
                            Content => $graph6_str ],
                ]);
  $ua->prepare_request ($req);
  print $req->as_string;

  my $resp = $ua->request($req);
  print $resp->as_string;

  exit 0;
}

sub Graph_Lai_Soltes_H4 {
  # Lai and Soltes H4
  # https://hog.grinvin.org/ViewGraphInfo.action?id=21117
  require Graph::Maker::Cycle;
  my $H4 = Graph::Maker->new('cycle', N=>10, undirected=>1);
  $H4->set_graph_attribute (name => 'Lai and Soltes H4');
  foreach my $parity (0, 1) {
    for (my $i = 1; $i <= 10; $i += 2) {
      for (my $j = $i+2; $j <= 10; $j += 2) {
        $H4->add_edge($i+$parity,$j+$parity);
      }
    }
  }
  return $H4;
}

sub Graph_Soltes_J2  {
  # Soltes J2
  # https://hog.grinvin.org/ViewGraphInfo.action?id=21113
  #      a----e
  #     / \   |\
  #    b---c  | g--h
  #     \ /   |/
  #      d----f
  #
  require Graph;
  my $J2 = Graph->new (undirected => 1);
  $J2->set_graph_attribute (name => 'J2');
  $J2->add_edge('a','b');$J2->add_edge('a','c');$J2->add_edge('a','e');
  $J2->add_edge('b','c');$J2->add_edge('b','d');
  $J2->add_edge('c','d');
  $J2->add_edge('d','f');
  $J2->add_edge('e','f');$J2->add_edge('e','g');
  $J2->add_edge('f','g');
  $J2->add_edge('g','h');
  return $J2;
}
sub Graph_Soltes_J3 {
  # Soltes J3
  #      a---                  misprint should b--c so that Soltes G3
  #     / \   \                = Beineke G2 is a subgraph
  #    b---c   e
  #     \ / _/ |
  #      d-/---f----g
  # hog not
  #
  require Graph;
  my $J3 = Graph->new (undirected => 1);
  $J3->set_graph_attribute (name => 'J3');
  $J3->add_edge('a','b');$J3->add_edge('a','c');$J3->add_edge('a','e');
  $J3->add_edge('b','c');$J3->add_edge('b','d');
  $J3->add_edge('c','d');
  $J3->add_edge('d','e');$J3->add_edge('d','f');
  $J3->add_edge('e','f');
  $J3->add_edge('f','g');
  return $J3;
}

sub edge_aref_eccentricity {
  my ($edge_aref, $v) = @_;
  ### $v

  my $eccentricity = 0;
  my @edges = @$edge_aref;
  my @pending = ($v);
  while (@pending) {
    ### @edges
    ### @pending
    $eccentricity++;
    my @new_pending;
    foreach my $v (@pending) {
      @edges = grep {
        my ($from,$to) = @$_;
        my $keep = 1;
        if ($from == $v) {
          push @new_pending, $to;
          $keep = 0;
        } elsif ($to == $v) {
          push @new_pending, $from;
          $keep = 0;
        }
        $keep
      } @edges;
    }
    @pending = @new_pending;
  }
  return $eccentricity;
}

sub Graph_theorem_of_the_day {
  my $g = Graph->new (undirected => 1);
  $g->add_edge('a','b'); $g->add_edge('a','d'); $g->add_edge('a','h');
  $g->add_edge('b','c'); $g->add_edge('b','d'); $g->add_edge('b','h');
  $g->add_edge('c','d'); $g->add_edge('c','e');
  $g->add_edge('c','g'); $g->add_edge('c','h');
  $g->add_edge('d','e'); $g->add_edge('d','f'); $g->add_edge('d','l');
  $g->add_edge('e','f'); $g->add_edge('e','l'); $g->add_edge('e','k');
  $g->add_edge('e','j'); $g->add_edge('e','g');
  $g->add_edge('f','l');
  $g->add_edge('g','j'); $g->add_edge('g','k'); $g->add_edge('g','l');
  $g->add_edge('g','i'); $g->add_edge('g','h');
  $g->add_edge('h','i'); $g->add_edge('h','l');
  $g->add_edge('i','l');
  $g->add_edge('j','k');
  $g->add_edge('k','l');
  $g->set_graph_attribute (name => 'Very Non-Line Graph');
  # $g->set_attribute('flow','south');
  # $g->set_attribute('root','a'); # for as_graphviz()
  # $g->{att}->{root} = 'a';       # for root_node() for as_ascii()
  return $g;
}
