in reply to Partial Order
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
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: Partial Order (cases)
by b4swine (Pilgrim) on Aug 14, 2007 at 01:57 UTC |