Algorithm-ConstructDFA

 view release on metacpan or  search on metacpan

t/02simple.t  view on Meta::CPAN

use Test::More;
use Algorithm::ConstructDFA;
use List::UtilsBy qw/sort_by/;
use List::MoreUtils qw/uniq/;
use Graph::Directed;
use Graph::RandomPath;

my $tests = 0;

for (1 .. 30) {
  my $g = Graph::Directed->random_graph(
    vertices   => int(rand(32)),
    edges_fill => 0.2
  );

  my %labels;
  my @vertices = $g->vertices;
  for my $v (@vertices) {
    next unless rand > 0.3;
    my $label = ['a', 'b', 'c']->[int rand 3];
    $g->set_vertex_attribute($v, 'label', $label);
  }
  
  my $start = [sort_by { scalar $g->successors($_) } @vertices]->[-1];
  
  next unless defined $start;
  
  my $final = [$g->all_successors($start), $start]
    ->[int rand(1 + scalar $g->all_successors($start))];
    
  next unless defined $final;
    
  my $dfa = construct_dfa(
    is_nullable  => sub {
      not $g->has_vertex_attribute($_[0], 'label')
    },
#    is_accepting => sub { grep { $_ eq $final } @_ },
    final => [ $final ],
    successors   => sub { $g->successors($_[0]) },
    get_label    => sub { $g->get_vertex_attribute($_[0], 'label') // '' },
    start        => [ $start ],
  );
  
  my $dfa_g = Graph::Directed->new;
  my $dfa_g_final = "final";
  for my $s (keys %$dfa) {
    for my $label (keys %{$dfa->{$s}{NextOver}}) {
      my $mid = $s . ':' . $label;
      $dfa_g->add_edge($s, $mid);
      $dfa_g->add_edge($mid, $dfa->{$s}{NextOver}{$label});
      $dfa_g->set_vertex_attribute($mid, 'label', $label) if length $label;
      $dfa_g->add_edge($s, $dfa_g_final)
        if $dfa->{$s}{Accepts};
      $dfa_g->add_edge($dfa->{$s}{NextOver}{$label}, $dfa_g_final)
        if $dfa->{$dfa->{$s}{NextOver}{$label}}{Accepts};
    }
  }

  my $make_random_path_enumerator = sub {
    return Graph::RandomPath->create_generator(@_);
    my ($graph, $src, $dst) = @_;
    my %to_src = map { $_ => 1 } $src, $graph->all_successors($src);
    my %to_dst = map { $_ => 1 } $dst, $graph->all_predecessors($dst);
    my $copy = Graph::Directed->new(edges => [ grep {
      $to_src{$_->[0]} and $to_src{$_->[1]} and
      $to_dst{$_->[0]} and $to_dst{$_->[1]}
    } $graph->edges]);

    return sub {
      my @path = ($src);
      for (1 .. int(rand(100))) {
        my $s = $copy->random_successor($path[-1]);
        last unless defined $s;
        push @path, $s;
      }
      unless ($path[-1] eq $dst) {
        splice @path, $#path, 1, $copy->SP_Dijkstra($path[-1], $dst);
      }
      return @path;
    }
  };

  for my $config ([$g, $start, $final, $dfa_g, 1, $dfa_g_final],
                  [$dfa_g, 1, $dfa_g_final, $g, $start, $final]
                  ) {

    my ($g1, $start, $final, $g2, $start2, $final2) = @$config;

    my $rnd;
    eval {
      $rnd = Graph::RandomPath->create_generator($g1, $start, $final);
    };
    next if $@;

    for (1 .. 4) {
      my @path =  $rnd->();
      
      my @word =
        map { $g1->get_vertex_attribute($_, 'label') } 
        grep { $g1->has_vertex_attribute($_, 'label') }
        @path[0 .. $#path - 1];

#      use YAML::XS;
#      warn Dump { path => \@path, word => join('/', @word),  };
        
      my @word_copy = @word;

      my @state = $start2;

      while (1) {
        my %seen;



( run in 0.614 second using v1.01-cache-2.11-cpan-140bd7fdf52 )