(invert): Rewrite as a product-of-sums to sum-of-products converter.
(_multiply, multiply): New functions.
* lib/Automake/Conditional.pm (not): New function.
* lib/Automake/tests/ConditionalSet.pl (test_invert): Update.
* automake.in (condition_negate): Move ...
* lib/Automake/Conditional.pm (negate_condition): ... here.
Suggested by Raja R Harinath.
+2002-11-20 Alexandre Duret-Lutz <adl@gnu.org>
+
+ * lib/Automake/ConditionalSet.pm (conds): Use value() to simplify.
+ (invert): Rewrite as a product-of-sums to sum-of-products converter.
+ (_multiply, multiply): New functions.
+ * lib/Automake/Conditional.pm (not): New function.
+ * lib/Automake/tests/ConditionalSet.pl (test_invert): Update.
+ * automake.in (condition_negate): Move ...
+ * lib/Automake/Conditional.pm (negate_condition): ... here.
+ Suggested by Raja R Harinath.
+
2002-11-19 Alexandre Duret-Lutz <adl@gnu.org>
* lib/Automake/ConditionalSet.pm (_simplify, simplify): New methods.
################################################################
-# $NEGATION
-# condition_negate ($COND)
-# ------------------------
-sub condition_negate ($)
-{
- my ($cond) = @_;
-
- $cond =~ s/TRUE$/TRUEO/;
- $cond =~ s/FALSE$/TRUE/;
- $cond =~ s/TRUEO$/FALSE/;
-
- return $cond;
-}
-
-
## ------------------------------ ##
## Handling the condition stack. ##
## ------------------------------ ##
$cond = "${cond}_TRUE"
unless $cond =~ /^TRUE|FALSE$/;
- $cond = condition_negate ($cond)
+ $cond = Automake::Conditional::condition_negate ($cond)
if $negate;
push (@cond_stack, $cond);
return;
}
- $cond_stack[$#cond_stack] = condition_negate ($cond_stack[$#cond_stack]);
+ $cond_stack[$#cond_stack] =
+ Automake::Conditional::condition_negate ($cond_stack[$#cond_stack]);
# If $COND is given, check against it.
if (defined $cond)
{
$cond = "${cond}_TRUE"
unless $cond =~ /^TRUE|FALSE$/;
- $cond = condition_negate ($cond)
+ $cond = Automake::Conditional::condition_negate ($cond)
if $negate;
err ($where, "else reminder ($negate$cond) incompatible with "
{
$cond = "${cond}_TRUE"
unless $cond =~ /^TRUE|FALSE$/;
- $cond = condition_negate ($cond)
+ $cond = Automake::Conditional::condition_negate ($cond)
if $negate;
err ($where, "endif reminder ($negate$cond) incompatible with "
# $other and $cond are implied by $both.)
@conds = Automake::Conditional::reduce ($other, $both, $cond);
+ # Invert a Conditional. This returns a ConditionalSet.
+ $set = $both->not;
+
=head1 DESCRIPTION
A C<Conditional> is a conjunction of atomic conditions. In Automake they
return 0;
}
+=item C<$cond-E<gt>not>
+
+Return a negation of @<$cond> as a list of C<Conditional>s.
+This list should be used to construct a C<ConditionalSet>
+(we cannot return a C<ConditionalSet> from C<Automake::Conditional>,
+because that would make these two packages interdependent).
+
+=cut
+
+sub not ($ )
+{
+ my ($self) = @_;
+ return @{$self->{'not'}} if defined $self->{'not'};
+ my @res;
+ for my $cond ($self->conds)
+ {
+ push @res, new Automake::Conditional &condition_negate ($cond);
+ }
+ $self->{'not'} = [@res];
+ return @res;
+}
+
=head2 Other helper functions
=over 4
return @ret;
}
+=item C<condition_negate ($condstr)>
+
+Negate a condition string.
+
+=cut
+
+sub condition_negate ($)
+{
+ my ($cond) = @_;
+
+ $cond =~ s/TRUE$/TRUEO/;
+ $cond =~ s/FALSE$/TRUE/;
+ $cond =~ s/TRUEO$/FALSE/;
+
+ return $cond;
+}
+
=head1 SEE ALSO
L<Automake::ConditionalSet>.
{
my ($self) = @_;
return @{$self->{'conds'}} if exists $self->{'conds'};
- my @conds = map { $self->{'hash'}{$_} } (keys %{$self->{'hash'}});
+ my @conds = values %{$self->{'hash'}};
@conds = sort { $a->string cmp $b->string } @conds;
$self->{'conds'} = [@conds];
return @conds;
return $res;
}
-=item C<$inv = $res-E<gt>invert>
+=item C<$prod = $set1->multiply ($set2)>
+
+Multiply to conditional sets.
+
+ my $set1 = new Automake::ConditionalSet
+ (new Automake::Conditional ("A_TRUE"),
+ new Automake::Conditional ("B_TRUE"));
+ my $set2 = new Automake::ConditionalSet
+ (new Automake::Conditional ("C_FALSE"),
+ new Automake::Conditional ("D_FALSE"));
+
+C<$set1-E<gt>multiply ($set2)> will return
+
+ new Automake::ConditionalSet
+ (new Automake::Conditional ("A_TRUE", "C_FALSE"),
+ new Automake::Conditional ("B_TRUE", "C_FALSE"),;
+ new Automake::Conditional ("A_TRUE", "D_FALSE"),
+ new Automake::Conditional ("B_TRUE", "D_FALSE"));
+
+=cut
+
+# Same as multiply() but take a list of Conditonal as second argument.
+# We use this in invert().
+sub _multiply ($@)
+{
+ my ($self, @set) = @_;
+ my @res = ();
+ foreach my $selfcond ($self->conds)
+ {
+ foreach my $setcond (@set)
+ {
+ push @res, $selfcond->merge ($setcond);
+ }
+ }
+ return new Automake::ConditionalSet @res;
+}
+
+sub multiply ($$)
+{
+ my ($self, $set) = @_;
+ return $self->_multiply ($set->conds);
+}
+
+=item C<$inv = $set-E<gt>invert>
Invert a C<ConditionalSet>. Return a C<ConditionalSet> which is true
-when C<$res> is false, and vice-versa.
+when C<$set> is false, and vice-versa.
my $set = new Automake::ConditionalSet
(new Automake::Conditional ("A_TRUE", "B_TRUE"),
return $self->{'invert'} if defined $self->{'invert'};
- # Generate permutations for all subconditions.
- my @perm = $self->permutations->conds;
-
- # Now remove all conditions which imply one of the input conditions.
- my @conds = $self->conds;
- my @notconds =
- grep { ! $_->implies_any (@conds) } $self->permutations->conds;
- my $res = new Automake::ConditionalSet @notconds;
+ # The invert of an empty ConditionalSet is TRUE.
+ my $res = new Automake::ConditionalSet TRUE;
+
+ # !((a.b)+(c.d)+(e.f))
+ # = (!a+!b).(!c+!d).(!e+!f)
+ # We develop this into a sum of product iteratively, starting from TRUE:
+ # 1) TRUE
+ # 2) TRUE.!a + TRUE.!b
+ # 3) TRUE.!a.!c + TRUE.!b.!c + TRUE.!a.!d + TRUE.!b.!d
+ # 4) TRUE.!a.!c.!e + TRUE.!b.!c.!e + TRUE.!a.!d.!e + TRUE.!b.!d.!e
+ # + TRUE.!a.!c.!f + TRUE.!b.!c.!f + TRUE.!a.!d.!f + TRUE.!b.!d.!f
+ foreach my $cond ($self->conds)
+ {
+ $res = $res->_multiply ($cond->not);
+ }
# Cache result.
$self->{'invert'} = $res;
[[["COND1_TRUE", "COND2_TRUE"],
["COND3_FALSE", "COND2_TRUE"]],
- [["COND1_FALSE","COND2_FALSE","COND3_FALSE"],
- ["COND1_TRUE", "COND2_FALSE","COND3_FALSE"],
- ["COND1_FALSE","COND2_FALSE","COND3_TRUE"],
- ["COND1_TRUE", "COND2_FALSE","COND3_TRUE"],
- ["COND1_FALSE","COND2_TRUE", "COND3_TRUE"]]],
+ [["COND2_FALSE"],
+ ["COND2_FALSE", "COND3_TRUE"],
+ ["COND1_FALSE", "COND2_FALSE"],
+ ["COND1_FALSE", "COND3_TRUE"]]],
[[["COND1_TRUE", "COND2_TRUE"],
["TRUE"]],
[[["COND1_TRUE", "COND2_TRUE"],
["FALSE"]],
- [["COND1_FALSE", "COND2_TRUE"],
- ["COND1_FALSE", "COND2_FALSE"],
- ["COND1_TRUE", "COND2_FALSE"]]],
+ [["COND1_FALSE"],
+ ["COND2_FALSE"]]],
[[["COND1_TRUE"],
["COND2_FALSE"]],
my $inv = $set->invert;
if ($inv != $res)
{
- print " (I) " . $inv->string . ' != ' . $res->string . "\n";
+ print " (I) " . $set->string . "\n\t"
+ . $inv->string . ' != ' . $res->string . "\n";
return 1;
}
}