http://qs1969.pair.com?node_id=41235

le has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

it's been a long time since I posted my last question here, but I've started my studies of CS and don't find a lot of time anymore.

Well, one of our first courses at the university is called "Introduction to programming" where we do stuff in Modula-2 (yeah). I always felt like "Hey how easy could this be done in Perl", but I resisted to annotate my thoughts in a comment in the source code :-)

One of the first examples we had to solve was the simplification of a boolean expression. The input looks like this
(abdc)(adc-b)
which aliases two boolean expressions. The terms inside the expressions are ANDed together, and the two expressions are ORed together (a negation is expressed with "-"), which means that the above string would be
(a AND b AND d AND c) OR (a AND d AND c AND NOT b)

Now boolean algebra says that one can simplify this expression if and only if the two partial expressions differ in just one negated variable, so the solution for the above example would be:
(adc)
The specification for this example was rather strict: Ok, I finished this example (and it was correct :-) ), but then I thought, just for fun, I do it in Perl, but now I just can't find a really cool "perlish" solution for this.

So I want to know if you guys (and ladies of course) can give a quick hack for this. (My Modula-2 programm was 202 lines long, pretty-formatted.)

Replies are listed 'Best First'.
Re: Boolean algebra
by chromatic (Archbishop) on Nov 13, 2000 at 09:33 UTC
    Here's the guts of the reduction. It's not particularly brilliant, but it seems to work in my testing. If it were not Sunday night, I might get elaborate with error checking or bit vectors, which would really be the way to go with this.

    There is room for someone to come along and to reduce my code's verbosity further. Welcommen.

    #!/usr/bin/perl -w use strict; my $input = "(abdc)(adc-b)"; my @expr; while ($input =~ s!\(([-a-z,]+)\)!!) { my @items = split '', $1; my (@and, @or) = (); while (@items) { my $elem = shift @items; if ($elem eq '-') { push @or, shift @items; } else { push @and, $elem; } } push @expr, [ \@and, \@or ]; } my $first = shift @expr; my @output = @{ @$first[0] }; while (my $next = shift @expr) { my (%keep, %drop); @keep{@{ @$next[0] }} = (); @drop{@{ @$next[1] }} = (); foreach (@output) { next if (exists $keep{$_}); $_ = undef if (exists $drop{$_}); } } my $output = join('', grep{ defined($_) } @output); print "Result is; $output\n";

    Update: I realized early this morning that this only handles the OR case in the second and subsequent input units. Back to the drawing board.

      Sorry, but your code is not correct (it works for this input but not for generic input).
Re: Boolean algebra
by snowcrash (Friar) on Nov 13, 2000 at 12:15 UTC
    if i get that specification right, chromatic's code doesn't work if there are negated elements that can't be reduced whitin the expression...
    for example, on input (a-b)(-a-b) the result would be nothing at all, and not (-b).

    yt, snowcrash
      Wrong, the result of (a-b)(-a-b) is (-b).
Re: Boolean algebra
by merlyn (Sage) on Nov 13, 2000 at 18:14 UTC
    I'd attempt this, but your specification is inconsistent, and as I was looking at it, I stopped working on it until you clarify. Specifically:
    • The order of variables in the output string had to be the same as the input string.
    This specification cannot be used with your sample data because you have the items delivered in different orders in the subexpressions: (abdc) vs (adc-b). So are you saying:
    1. that we're permitted to select a subexpression at random with which to comply, or
    2. that your sample data would never be the actual data, or
    3. that this rule can be tossed out?
    (Each of those yields a slightly different solution in my mind, because I can optimize for some things differently in each. {grin})

    -- Randal L. Schwartz, Perl hacker

      Maybe I wasn't clear.
      • The order of variables in the output string had to be the same as the input string.
      This means that
      (abc)(b-ac)
      and
      (cb-a)(bca)
      are equally correct input strings (they are even the same expression since (a AND b AND c) OR (b AND NOT a AND c) is the same as (c AND b AND NOT a) OR (b AND c AND a)).

      But the output of the first reduction would be

      (bc)
      and of the second reduction
      (cb)


      Of course there can be many negated variables like this:
      (-a-b-c-d)(-c-da-b)
      which would result in
      (-b-c-d)
        Why is the second one (cb) and not (bc), since both orderings are in the input string? What permits me to pick one subexpression over the other? You still aren't clear, and the specification is still ambiguous to me.

        -- Randal L. Schwartz, Perl hacker