diff --git a/macros/math/SimpleGraph.pl b/macros/math/SimpleGraph.pl index d498a735a..2b86c1b8b 100644 --- a/macros/math/SimpleGraph.pl +++ b/macros/math/SimpleGraph.pl @@ -135,7 +135,7 @@ sub randomGraphWithoutEulerTrail { my $graph; do { - $graph = simpleGraphWithDegreeSequence([ map { main::random(2, $size - 1, 1) } 0 .. $size - 1 ], %options); + $graph = simpleGraphWithDegreeSequence([ map { main::random(2, $size - 1) } 0 .. $size - 1 ], %options); } while !defined $graph || $graph->hasEulerTrail; return $graph->setRandomWeights( @@ -543,7 +543,7 @@ sub edgeSet { } } - my $edgeSet = GraphTheory::SimpleGraph::Value::EdgeSet->new($context, @edgeSet); + my $edgeSet = GraphTheory::SimpleGraph::Value::EdgeSet->new($context, \@edgeSet); $edgeSet->{open} = '{'; $edgeSet->{close} = '}'; return $edgeSet; @@ -645,6 +645,37 @@ sub numComponents { return $result; } +sub components { + my $self = shift; + + my @adjacencyMatrix = map { [@$_] } @{ $self->{adjacencyMatrix} }; + + for my $i (0 .. $#adjacencyMatrix) { + for my $j ($i + 1 .. $#adjacencyMatrix) { + if ($adjacencyMatrix[$i][$j] != 0) { + for my $k (0 .. $#adjacencyMatrix) { + $adjacencyMatrix[$j][$k] += $adjacencyMatrix[$i][$k]; + $adjacencyMatrix[$k][$j] += $adjacencyMatrix[$k][$i]; + } + } + } + } + + my @components; + for my $i (reverse(0 .. $#adjacencyMatrix)) { + my $componentFound = 0; + for (@components) { + next unless $adjacencyMatrix[ $_->[-1] ][$i]; + $componentFound = 1; + unshift(@$_, $i); + last; + } + push(@components, [$i]) unless $componentFound; + } + + return main::PGsort(sub { $_[0][0] < $_[1][0] }, @components); +} + sub edgeWeight { my ($self, $i, $j, $weight) = @_; if (defined $weight) { @@ -796,11 +827,10 @@ sub image { $plot->add_point(@$iVertex, color => 'blue', mark_size => 3); $plot->add_label( - 1.25 * $iVertex->[0], 1.25 * $iVertex->[1], - label => "\\\\($self->{labels}[$i]\\\\)", + $iVertex->[0], $iVertex->[1], "\\\\($self->{labels}[$i]\\\\)", color => 'blue', - h_align => 'center', - v_align => 'middle' + anchor => 180 + $i * $gap * 180 / $main::PI, + padding => 8 ) if $graphOptions{showLabels}; my $u = 0.275; @@ -818,8 +848,8 @@ sub image { $plot->add_label( $u * $iVertex->[0] + $v * $jVertex->[0] + $perp[0] * 0.06, $u * $iVertex->[1] + $v * $jVertex->[1] + $perp[1] * 0.06, - label => "\\\\($self->{adjacencyMatrix}->[$i][$j]\\\\)", - color => 'red', + "\\\\($self->{adjacencyMatrix}->[$i][$j]\\\\)", + color => 'FireBrick', rotate => ($perp[0] < 0 ? 1 : -1) * atan2(sqrt(1 - $perp[1] * $perp[1]), $perp[1]) * 180 / $main::PI - ($perp[1] < 0 ? 180 : 0) @@ -867,11 +897,10 @@ sub gridLayoutImage { my $y = $gridGap * ($self->{gridLayout}[0] - $i - 1); $plot->add_point($x, $y, color => 'blue', mark_size => 3); $plot->add_label( - $x - $labelShift, $y + 2 * $labelShift, - label => "\\\\($self->{labels}[$i + $self->{gridLayout}[0] * $j]\\\\)", + $x, $y, "\\\\($self->{labels}[$i + $self->{gridLayout}[0] * $j]\\\\)", color => 'blue', - h_align => 'center', - v_align => 'middle' + anchor => -atan2(2, 1) * 180 / $main::PI, + padding => 8, ) if $graphOptions{showLabels}; } } @@ -891,14 +920,14 @@ sub gridLayoutImage { ($self->{gridLayout}[0] - ($j % $self->{gridLayout}[0]) - 1) * $gridGap ]; $plot->add_dataset($iVertex, $jVertex, color => 'black', width => 1); - my $vector = [ $jVertex->[0] - $iVertex->[0], $jVertex->[1] - $iVertex->[1] ]; if ($graphOptions{showWeights}) { - my $norm = sqrt($vector->[0]**2 + $vector->[1]**2); + my $vector = [ $jVertex->[0] - $iVertex->[0], $jVertex->[1] - $iVertex->[1] ]; $plot->add_label( - $u * $iVertex->[0] + $v * $jVertex->[0] - $vector->[1] / $norm * 2, - $u * $iVertex->[1] + $v * $jVertex->[1] + $vector->[0] / $norm * 2, - label => "\\\\($self->{adjacencyMatrix}[$i][$j]\\\\)", - color => 'red' + $u * $iVertex->[0] + $v * $jVertex->[0], + $u * $iVertex->[1] + $v * $jVertex->[1], + "\\\\($self->{adjacencyMatrix}[$i][$j]\\\\)", + color => 'FireBrick', + anchor => atan2(-$vector->[0], $vector->[1]) * 180 / $main::PI ); } } @@ -969,21 +998,21 @@ sub bipartiteLayoutImage { for my $i (0 .. $#$top) { $plot->add_point($i * $width + $shift[0], $high, color => 'blue', mark_size => 3); $plot->add_label( - $i * $width + $shift[0], $high + 2 / 3, - label => "\\\\($self->{labels}[$top->[$i]]\\\\)", + $i * $width + $shift[0], $high, "\\\\($self->{labels}[$top->[$i]]\\\\)", color => 'blue', h_align => 'center', - v_align => 'bottom' + v_align => 'bottom', + padding => 8 ) if $graphOptions{showLabels}; } for my $j (0 .. $#$bottom) { $plot->add_point($j * $width + $shift[1], $low, color => 'blue', mark_size => 3); $plot->add_label( - $j * $width + $shift[1], $low - 2 / 3, - label => "\\\\($self->{labels}[$bottom->[$j]]\\\\)", + $j * $width + $shift[1], $low, "\\\\($self->{labels}[$bottom->[$j]]\\\\)", color => 'blue', h_align => 'center', - v_align => 'top' + v_align => 'top', + padding => 8 ) if $graphOptions{showLabels}; } @@ -997,12 +1026,13 @@ sub bipartiteLayoutImage { $plot->add_dataset($point1, $point2, color => 'black'); if ($graphOptions{showWeights}) { my $vector = [ $point2->[0] - $point1->[0], $point2->[1] - $point1->[1] ]; - my $norm = sqrt($vector->[0]**2 + $vector->[1]**2); $plot->add_label( - $u * $point1->[0] + $v * $point2->[0] - $vector->[1] / $norm * 5 / 4, - $u * $point1->[1] + $v * $point2->[1] + $vector->[0] / $norm * 5 / 4, - label => "\\\\($self->{adjacencyMatrix}[ $top->[$i] ][ $bottom->[$j] ]\\\\)", - color => 'red' + $u * $point1->[0] + $v * $point2->[0], + $u * $point1->[1] + $v * $point2->[1], + "\\\\($self->{adjacencyMatrix}[ $top->[$i] ][ $bottom->[$j] ]\\\\)", + color => 'FireBrick', + anchor => atan2($vector->[0], -$vector->[1]) * 180 / $main::PI + 180, + padding => 2 ); } } @@ -1039,11 +1069,10 @@ sub wheelLayoutImage { $plot->add_point(0, 0, color => 'blue', mark_size => 3); $plot->add_label( - 0.1, 0.2, - label => "\\\\($self->{labels}[ $self->{wheelLayout} ]\\\\)", + 0, 0, "\\\\($self->{labels}[ $self->{wheelLayout} ]\\\\)", color => 'blue', - h_align => 'center', - v_align => 'middle' + anchor => 180 + $gap * 90 / $main::PI, + padding => 10 ) if $graphOptions{showLabels}; for my $i (0 .. $self->lastVertexIndex) { @@ -1055,11 +1084,10 @@ sub wheelLayoutImage { $plot->add_point(@$iVertex, color => 'blue', mark_size => 3); $plot->add_label( - 1.25 * $iVertex->[0], 1.25 * $iVertex->[1], - label => "\\\\($self->{labels}[$i]\\\\)", + $iVertex->[0], $iVertex->[1], "\\\\($self->{labels}[$i]\\\\)", color => 'blue', - h_align => 'center', - v_align => 'middle' + anchor => 180 + $iRel * $gap * 180 / $main::PI, + padding => 8 ) if $graphOptions{showLabels}; if ($self->hasEdge($self->{wheelLayout}, $i)) { @@ -1070,8 +1098,8 @@ sub wheelLayoutImage { $plot->add_label( 0.5 * $iVertex->[0] + $iVertex->[1] / $norm * 0.1, 0.5 * $iVertex->[1] - $iVertex->[0] / $norm * 0.1, - label => "\\\\($self->{adjacencyMatrix}->[ $self->{wheelLayout} ][$i]\\\\)", - color => 'red', + "\\\\($self->{adjacencyMatrix}->[ $self->{wheelLayout} ][$i]\\\\)", + color => 'FireBrick', rotate => ($perp[0] < 0 ? 1 : -1) * atan2(sqrt(1 - $perp[1] * $perp[1]), $perp[1]) * 180 / $main::PI - ($perp[1] < 0 ? 180 : 0) @@ -1095,8 +1123,8 @@ sub wheelLayoutImage { $plot->add_label( 0.5 * $iVertex->[0] + 0.5 * $jVertex->[0] + $vector[1] / $norm * 0.1, 0.5 * $iVertex->[1] + 0.5 * $jVertex->[1] - $vector[0] / $norm * 0.1, - label => "\\\\($self->{adjacencyMatrix}->[$i][$j]\\\\)", - color => 'red', + "\\\\($self->{adjacencyMatrix}->[$i][$j]\\\\)", + color => 'FireBrick', rotate => ($perp[0] < 0 ? 1 : -1) * atan2(sqrt(1 - $perp[1] * $perp[1]), $perp[1]) * 180 / $main::PI - ($perp[1] < 0 ? 180 : 0) @@ -2242,6 +2270,13 @@ =head2 numComponents This method returns the number of connected components in the graph. +=head2 components + + @c = $graph->components; + +This method returns an array containing references to arrays that form a +partition of the vertex indices into the connected components of the graph. + =head2 edgeWeight $c = $graph->edgeWeight($i, $j);