The complexity in your code is due to having to code all of the combining of cases, each in two directions. Simply using two bits, one for '<=', one for '>=', means that the cases can be combined with a simple bit-wise &, greatly reducing the repetition in the code.

I also moved the checking for special cases to places where each case only needs to be checked once, eliminating many of the checks. Many operations will be done more than once in building the data structure, but the code is simpler.

#!/usr/bin/perl -w use strict; sub UNK() { 0; } sub LTE() { 1; } sub GTE() { 2; } sub EQU() { 3; } my $Pref= {}; my %OpBits= ( '<' => LTE(), '>' => GTE(), '=' => EQU(), ); my %RevBits= ( UNK() => UNK(), LTE() => GTE(), GTE() => LTE(), EQU() => EQU(), ); Main( @ARGV ); exit( 0 ); sub onePref { my( $x, $bits, $y )= @_; return if $bits == UNK(); if( $Pref->{$x} && exists $Pref->{$x}{$y} ) { die "ERROR contradictory $x $y\n" if $Pref->{$x}{$y} != $bits; } else { $Pref->{$x}{$y}= $bits; $Pref->{$y}{$x}= $RevBits{$bits}; } } sub allPrefs { my( $x, $c, $y )= @_; my $bits= $OpBits{$c}; $Pref->{$x}{$x}= $Pref->{$y}{$y}= EQU(); onePref( $x, $bits, $y ); while( my($z,$v)= each %{$Pref->{$y}} ) { onePref( $x, $bits & $v, $z ); } $bits= $RevBits{$bits}; while( my($z,$v)= each %{$Pref->{$x}} ) { onePref( $y, $bits & $v, $z ); } } sub partialOrder { for my $chain ( @_ ) { while( $chain =~ /\G\s*(\w+)\s*([<=>])\s*(?=(\w+))/gc ) { my( $x, $c, $y )= ( $1, $2, $3 ); allPrefs( $x, $c, $y ); } if( $chain !~ /\G\s*(\w+)\s*$/g ) { die "Invalid preferences ($chain).\n"; } } } sub compare { my( $x, $y )= @_; return $Pref->{$x}{$y} || UNK(); } sub Main { partialOrder( 'xx < yy < zz > aa', 'bb < yy = aa > cc', ); my @vals= sort keys %$Pref; my %bitVal= ( UNK() => '.', LTE() => '-', GTE() => '+', EQU() => '=', ); my $len= 1; for( map length($_), @vals ) { $len= $_ if $len < $_; } for my $v ( @vals ) { $v= sprintf "%-*s", $len, $v; } print "Comparison Table:\n"; print join " ", ' 'x$len, @vals; print $/; for my $x ( @vals ) { print "$x "; for my $y ( @vals ) { my $c= compare( $x, $y ); printf "%-*s", 1+$len, $bitVal{$c}; } print "\n"; } partialOrder( 'ww < ww' ); }

Update: The code simplifies even further by moving one of the "do both directions" responsibilities up one level in the call stack:

sub allPrefs { my( $x, $bits, $y )= @_; $Pref->{$x}{$x}= EQU(); onePref( $x, $bits, $y ); while( my($z,$v)= each %{$Pref->{$y}} ) { onePref( $x, $bits & $v, $z ); } } sub partialOrder { for my $chain ( @_ ) { while( $chain =~ /\G\s*(\w+)\s*([<=>])\s*(?=(\w+))/gc ) { my( $x, $c, $y )= ( $1, $2, $3 ); my $bits= $OpBits{$c}; allPrefs( $x, $bits, $y ); allPrefs( $y, $RevBits{$bits}, $x ); } if( $chain !~ /\G\s*(\w+)\s*$/g ) { die "Invalid preferences ($chain).\n"; } } }

- tye        


In reply to Re: Partial Order (cases) by tye
in thread Partial Order by b4swine

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.