=head1 NAME
Math::Logic - Provides pure 2, 3 or multi-value logic.
=head1 SYNOPSIS
use Math::Logic qw( TRUE FALSE UNDEF STR_TRUE STR_FALSE STR_UNDEF ) ;
# 1 0 -1 'TRUE' 'FALSE' 'UNDEF'
use Math::Logic ':NUM' ; # TRUE FALSE UNDEF -- what you normally want
use Math::Logic ':ALL' ; # All the constants
use Math::Logic ':STR' ; # STR_TRUE STR_FALSE STR_UNDEF
# 2-value logic
my $true = Math::Logic->new( -value => TRUE, -degree => 2 ) ;
my $false = Math::Logic->new( -value => FALSE, -degree => 2 ) ;
my $x = Math::Logic->new_from_string( 'TRUE,2' ) ;
print "true" if $true ;
# 3-value logic (non-propagating)
my $true = Math::Logic->new( -value => TRUE, -degree => 3 ) ;
my $false = Math::Logic->new( -value => FALSE, -degree => 3 ) ;
my $undef = Math::Logic->new( -value => UNDEF, -degree => 3 ) ;
my $x = Math::Logic->new_from_string( 'FALSE,3' ) ;
print "true" if ( $true | $undef ) == TRUE ;
# 3-value logic (propagating)
my $true = Math::Logic->new( -value => TRUE, -degree => 3, -propagate => 1 ) ;
my $false = Math::Logic->new( -value => FALSE, -degree => 3, -propagate => 1 ) ;
my $undef = Math::Logic->new( -value => UNDEF, -degree => 3, -propagate => 1 ) ;
my $x = Math::Logic->new_from_string( '( UNDEF, 3, -propagate )' ) ;
print "undef" if ( $true | $undef ) == UNDEF ;
# multi-value logic
my $TRUE = 100 ; # Define our own true
my $FALSE = FALSE ;
my $true = Math::Logic->new( -value => $TRUE, -degree => $TRUE ) ;
my $very = Math::Logic->new( -value => 67, -degree => $TRUE ) ;
my $fairly = Math::Logic->new( -value => 33, -degree => $TRUE ) ;
my $false = Math::Logic->new( -value => $FALSE, -degree => $TRUE ) ;
my $x = Math::Logic->new_from_string( "25,$TRUE" ) ;
print "maybe" if ( $very | $fairly ) > 50 ;
=head1 DESCRIPTION
Perl's built-in logical operators, C<and>, C<or>, C<xor> and C<not> support
2-value logic. This means that they always produce a result which is either
true or false. In fact perl sometimes returns 0 and sometimes returns undef
for false depending on the operator and the order of the arguments. For "true"
Perl generally returns the first value that evaluated to true which turns out
to be extremely useful in practice. Given the choice Perl's built-in logical
operators are to be preferred -- but when you really want pure 2-value logic
or 3-value logic or multi-value logic they are available through this module.
The only 2-value logic values are 1 (TRUE) and 0 (FALSE).
The only 3-value logic values are 1 (TRUE), 0 (FALSE) and -1 (UNDEF). Note
that UNDEF is -1 I<not> C<undef>!
The only multi-value logic values are 0 (FALSE)..C<-degree> -- the value of
TRUE is equal to the degree, usually 100.
Although some useful constants may be exported, this is an object module and
the results of logical comparisons are Math::Logic objects.
=head2 2-value logic
2-value logic has one simple truth table for each logical operator.
Perl Logic Perl Logic Perl Logic
A B and and A B or or A B xor xor
- - --- --- - - -- -- - - --- ---
F F F F F F F F F F F F
T T T T T T T T T T F F
T F F F T F T T T F T T
F T F F F T T T F T T T
Perl Logic
A not not
- --- ---
F T T
T F F
In the above tables when dealing with Perl's built-in logic T and F are any
true and any false value respectively; with Math::Logic they are objects whose
values are 1 and 0 respectively. Note that whilst Perl may return 0 or undef
for false and any other value for true, Math::Logic returns an object whose
value is either 0 (FALSE) or 1 (TRUE) only.
my $true = Math::Logic->new( -value => TRUE, -degree => 2 ) ;
my $false = Math::Logic->new( -value => FALSE, -degree => 2 ) ;
my $result = $true & $false ; # my $result = $true->and( $false ) ;
print $result if $result == FALSE ;
=head2 3-value logic
3-value logic has two different truth tables for "and" and "or"; this module
supports both. In the Perl column F means false or undefined; and T, F and U
under Math::Logic are objects with values 1 (TRUE), 0 (FALSE) and -1 (UNDEF)
respectively. The + signifies propagating nulls (UNDEFs).
Perl Logic Perl Logic Perl Logic
A B and and+ and A B or or+ or A B xor xor+ xor(same)
- - --- --- --- - - -- -- -- - - --- --- ---
U U F U U U U F U U U U F U U
U F F U F U F F U U U F F U U
F U F U F F U F U U F U F U U
F F F F F F F F F F F F F F F
U T F U U U T T U T U T T U U
T U F U U T U T U T T U T U U
T T T T T T T T T T T T F F F
T F F F F T F T T T T F T T T
F T F F F F T T T T F T T T T
Perl Logic
A not not+ not(same)
- --- --- ---
U T U U
U T U U
F T T T
T F F F
# 3-value logic (non-propagating)
my $true = Math::Logic->new( -value => TRUE, -degree => 3 ) ;
my $false = Math::Logic->new( -value => FALSE, -degree => 3 ) ;
my $undef = Math::Logic->new( -value => UNDEF, -degree => 3 ) ;
my $result = $undef & $false ; # my $result = $undef->and( $false ) ;
print $result if $result == FALSE ;
# 3-value logic (propagating)
my $true = Math::Logic->new( -value => TRUE, -degree => 3, -propagate => 1 ) ;
my $false = Math::Logic->new( -value => FALSE, -degree => 3, -propagate => 1 ) ;
my $undef = Math::Logic->new( -value => UNDEF, -degree => 3, -propagate => 1 ) ;
my $result = $undef & $false ; # my $result = $undef->and( $false ) ;
print $result if $result == UNDEF ;
=head2 multi-value logic
This is used in `fuzzy' logic. Typically we set the C<-degree> to 100
representing 100% likely, i.e. true; 0 represents 0% likely, i.e. false, and
any integer in-between is a probability.
The truth tables for multi-value logic work like this:
C<and> lowest value is the result;
C<or> highest value is the result;
C<xor> highest value is the result
unless they're the same in which case the result is FALSE;
C<not> degree minus the value is the result.
Logic
A B and or xor
--- --- --- --- ---
0 0 0 0 0
0 100 0 100 100
100 0 0 100 100
100 100 100 100 0
0 33 0 33 33
33 0 0 33 33
33 100 33 100 33
33 33 33 33 0
100 33 33 100 100
0 67 0 67 67
67 0 0 67 67
67 100 67 100 100
67 67 67 67 0
100 67 67 100 100
33 67 33 67 67
67 33 33 67 67
A not
--- ---
0 100
33 67
67 33
100 0
# multi-value logic
my $TRUE = 100 ; # Define our own TRUE and FALSE
my $FALSE = FALSE ;
$true = Math::Logic->new( -value => $TRUE, -degree => $TRUE ) ;
$very = Math::Logic->new( -value => 67, -degree => $TRUE ) ;
$fairly = Math::Logic->new( -value => 33, -degree => $TRUE ) ;
$false = Math::Logic->new( -value => $FALSE, -degree => $TRUE ) ;
my $result = $fairly & $very ; # my $result = $fairly->and( $very ) ;
print $result if $result == $fairly ;
=head2 Public methods
new class object (also used for assignment)
new_from_string class object
value object
degree object
propagate object
incompatible object
compatible object (deprecated)
as_string object
and object (same as &)
or object (same as |)
xor object (same as ^)
not object (same as !)
"" object (see as_string)
0+ object (automatically handled)
<=> object (comparisons)
& object (logical and)
| object (logical or)
^ object (logical xor)
! object (logical not)
=head2 new (class and object method)
my $x = Math::Logic->new ;
my $y = Math::Logic->new( -value => FALSE, -degree => 3, -propagate => 0 );
my $a = $x->new ;
my $b = $y->new( -value => TRUE ) ;
This creates new Math::Logic objects. C<new> should never fail because it will
munge any arguments into something `sensible'.
If used as an object method, e.g. for assignment then the settings are those
of the original object unless overridden. If used as a class method with no
arguments then default values are used.
C<-degree> an integer indicating the number of possible truth values;
typically set to 2, 3 or 100 (to represent percentages). Minimum value is 2.
C<-propagate> a true/false integer indicating whether NULLs (UNDEF) should
propagate; only applicable for 3-value logic where it influences which truth
table is used.
C<-value> an integer representing the truth value. For 2-value logic only 1
and 0 are valid (TRUE and FALSE); for 3-value logic 1, 0, and -1 are valid
(TRUE, FALSE and UNDEF); for multi-value logic any positive integer less than
or equal to the C<-degree> is valid.
=head2 new_from_string (class and object method)
my $x = Math::Logic->new_from_string( '1,2' ) ;
my $y = Math::Logic->new_from_string( 'TRUE,3,-propagate' ) ;
my $z = Math::Logic->new_from_string( '( FALSE, 3, -propagate )' ) ;
my $m = Math::Logic->new_from_string( '33,100' ) ;
my $n = Math::Logic->new_from_string( '67%,100' ) ;
This creates new Math::Logic objects. The string B<must> include the first two
values, which are C<-value> and C<-degree> respectively.
=head2 value (object method)
print $x->value ;
print $x ;
This returns the numeric value of the object. For 2-value logic this will
always be 1 or 0; for 3-value logic the value will be 1, 0 or -1; for
multi-value logic the value will be a positive integer <= C<-degree>.
=head2 degree (object method)
print $x->degree ;
This returns the degree of the object, i.e. the number of possible truth
values the object may hold; it is always 2 or more.
=head2 propagate (object method)
print $x->propagate ;
This returns whether or not the object propagates NULLs (UNDEF). Objects using
2 or multi-value logic always return FALSE; 3-value logic objects may return
TRUE or FALSE.
=head2 incompatible (object method)
print $x & $y unless $x->incompatible( $y ) ;
Returns FALSE if the objects are compatible; returns an error string if
incompatible (which Perl treats as TRUE), e.g.:
$x = Math::Logic->new_from_string('1,2') ;
$y = Math::Logic->new_from_string('0,3') ;
# The above are incompatible because the first uses 2-value logic and the
# second uses 3-value logic.
print $x->incompatible( $y ) if $x->incompatible( $y ) ;
# This will print something like:
Math::Logic(2,0) and Math::Logic(3,0) are incompatible at ./logic.t line 2102
# The first number given is the degree and the second the propagate setting
Objects are compatible if they have the same C<-degree> and in the case of
3-value logic the same C<-propagate>. Logical operators will only work on
compatible objects, there is no type-coersion (but see typecasting later).
=head2 compatible DEPRECATED (object method)
print $x->compatible( $y ) ;
Returns TRUE or FALSE depending on whether the two objects are compatible.
Objects are compatible if they have the same C<-degree> and in the case of
3-value logic the same C<-propagate>. Logical operators will only work on
compatible objects, there is no type-coersion (but see typecasting later).
=head2 as_string and "" (object method)
# output:
print $x->as_string ; # TRUE
print $x->as_string( 1 ) ; # (TRUE,2)
print $x->as_string( -full ) ; # (TRUE,2)
print $x ; # TRUE
print $x->value ; # 1
print $m ; # 33
print $m->value ; # 33
print $m->as_string( 1 ) ; # (33%,100)
Usually you won't have to bother using C<as_string> since Perl will invoke it
for you as necessary; however if you want a string that can be saved, (perhaps
to be read in using C<new_from_string> later), you can pass an argument to
C<as_string>.
=head2 and and & (object method)
print "true" if ( $y & $z ) == TRUE ;
print "yes" if $y & 1 ;
print "yes" if TRUE & $y ;
$r = $y & $z ; # Creates a new Math::Logic object with the resultant truth value
print "true" if $y->and( $z ) == TRUE ;
Applies logical and to two objects. The truth table used depends on the
object's C<-degree> (and in the case of 3-value logic on the C<-propagate>).
(See the truth tables above.)
=head2 or and | (object method)
print "true" if ( $y | $z ) == TRUE ;
print "yes" if $y | 1 ;
print "yes" if TRUE | $y ;
$r = $y | $z ; # Creates a new Math::Logic object with the resultant truth value
print "true" if $y->or( $z ) == TRUE ;
Applies logical or to two objects. The truth table used depends on the
object's C<-degree> (and in the case of 3-value logic on the C<-propagate>).
(See the truth tables above.)
=head2 xor and ^ (object method)
print "true" if ( $y ^ $z ) == TRUE ;
print "yes" if $y ^ 0 ;
print "yes" if TRUE ^ $y ;
$r = $y ^ $z ; # Creates a new Math::Logic object with the resultant truth value
print "true" if $y->xor( $z ) == TRUE ;
Applies logical xor to two objects. The truth table used depends on the
object's C<-degree>. (See the truth tables above.)
=head2 not and ! (object method)
print "true" if ! $y == TRUE ;
$r = ! $y ; # Creates a new Math::Logic object with the resultant truth value
print "true" if $y->not == TRUE ;
Applies logical not to the object. The truth table used depends on the
object's C<-degree>. (See the truth tables above.)
=head2 comparisons and <=> (object method)
All the standard (numeric) comparison operators may be applied to Math::Logic
objects, i.e. <, <=, >, =>, ==, != and <=>.
=head2 typecasting
The only typecasting that appears to make sense is between 2 and 3-value
logic. There is no direct support for it but it can be achieved thus:
my $x = Math::Logic->new_from_string( '1,2' ) ; # TRUE 2-value
my $y = Math::Logic->new_from_string( '0,3' ) ; # FALSE 3-value
my $z = Math::Logic->new_from_string( '-1,3' ) ; # UNDEF 3-value
$x3 = $x->new( -degree => 3 ) ;
$y2 = $y->new( -degree => 2 ) ;
$z2 = $y->new( -degree => 2 ) ; # UNDEF converted silently to FALSE
=head1 BUGS
(none known)
=head1 CHANGES
2000/02/21
Added incompatible method and now deprecate compatible method; this provides
better error messages; updated test script.
2000/02/20
Minor documentation fixes. Also eliminated a warning that occurred under
5.005.
2000/02/19
First version. Ideas taken from my Math::Logic3 and (unpublished) Math::Fuzzy;
this module is intended to supercede both.
=head1 AUTHOR
Mark Summerfield. I can be contacted as <summer@perlpress.com> -
please include the word 'logic' in the subject line.
=head1 COPYRIGHT
Copyright (c) Mark Summerfield 2000. All Rights Reserved.
This module may be used/distributed/modified under the LGPL.
=cut