Algorithm-DependencySolver
view release on metacpan or search on metacpan
lib/Algorithm/DependencySolver/Solver.pm view on Meta::CPAN
}
return \@relations;
}
method build_Graph() {
my @vertices = keys %{$self->get_nodes_index};
my @edges = map {
[ $_->[0]->id, $_->[1]->id ]
} @{$self->get_relations};
# Ensure that each explicit ordering (node.prerequisites) has an edge.
for my $nodeB (@{$self->get_nodes}) {
for my $nodeA_id (@{$nodeB->prerequisites}) {
push @edges, [$nodeA_id, $nodeB->id];
}
}
my $G = Graph::Directed->new(
vertices => \@vertices,
edges => \@edges,
# refvertexed => 1, # refvertexed is broken!
);
# Note: Graph::Traversal has a bug in it where noderefs are
# sometimes stringified, even though they mustn't be with
# refvertexed! Therefore, assume all of Graph is broken in this
# respect, and never pass in addresses to references, but never
# references themselves.
$self->_apply_orderings($G);
$self->_remove_redundancy($G);
return $G;
}
method _get_nondeterministic_attributes() {
my %nondep_affects;
AFFECT:
for my $affect (keys %{$self->get_affects_index}) {
my @node_ids = map {
$_->id
} @{$self->get_affects_index->{$affect}};
next AFFECT unless @node_ids;
my @sequentials;
for my $node_id (@node_ids) {
my @pred_ids = $self->get_Graph->all_predecessors($node_id);
push @pred_ids, $node_id;
my $C = List::Compare->new(\@node_ids, \@pred_ids);
if ($C->is_LsubsetR) {
# We're good; we have a nice linear ordering
next AFFECT;
} else {
my @intersection = $C->get_intersection;
if (@intersection > @sequentials) {
@sequentials = @intersection;
}
}
}
# Nondeterministic affect!
my @nondeps = List::Compare->new(\@node_ids, \@sequentials)->get_unique;
$nondep_affects{$affect} = {
sequentials => \@sequentials,
nondeps => \@nondeps,
};
}
return keys(%nondep_affects) ? \%nondep_affects : undef;
}
method _get_undepended_affects() {
my %undeped_affects;
AFFECT:
for my $affect (keys %{$self->get_affects_index}) {
my @nodes = @{$self->get_affects_index->{$affect}};
next AFFECT unless @nodes;
for my $node (@nodes) {
my $f;
$f = sub {
my $suc_id = shift;
my $suc = $self->get_nodes_index->{$suc_id};
if ($suc->depends($affect)) {
# This path is good
return [];
} elsif ($suc->affects($affect)) {
# woah
return [$suc];
} else {
return [map { @{$f->($_)} } $self->get_Graph->successors($suc_id)];
}
};
my @bad = map { @{$f->($_)} } $self->get_Graph->successors($node->id);
$undeped_affects{$affect}{$node->id} = \@bad if @bad;
}
}
return keys(%undeped_affects) ? \%undeped_affects : undef;
}
method is_invalid() {
my $cyclic = $self->get_Graph->is_cyclic;
my $nondeterministic = $self->_get_nondeterministic_attributes;
my $undeped_affects = $self->_get_undepended_affects;
my %r;
$r{cyclic} = $cyclic if $cyclic;
$r{nondeterministic} = $nondeterministic if $nondeterministic;
$r{undeped_affects} = $undeped_affects if $undeped_affects;
if (keys %r) {
return \%r;
} else {
return;
}
( run in 0.573 second using v1.01-cache-2.11-cpan-39bf76dae61 )