Exotic Logics

W

William Clifford

I was staring at a logic table the other day, and I asked myself,
"what if one wanted to play with exotic logics; how might one do it?"
I did some searching but not being too sure of what to look for and
carried away with my own enthusiasm for the idea, I didn't find much.
What I've come up with is, no doubt, inefficient, naive, poor python
style, and probably wrong in fundamental ways too subtle for me, but
here it is:

import itertools
import operator

class Logic():
"""class of generic logic operators"""

@staticmethod
def lsd(rdx, n):
"""yield up base rdx digits of n in least significant order"""
while n > 0:
q, r = divmod(n, rdx)
n = q
yield r

@staticmethod
def rdxn(rdx, seq):
"""reduce a sequence of numbers by powers of rdx"""
return reduce(operator.add,
map(operator.mul,
seq, (pow(rdx, i) for i in range(len(seq)))))

@staticmethod
def pute(rdx, opr, arg):
"""a logical primitive which returns 0 or 1."""
if arg < 0:
return 0
o = tuple(lsd(rdx, opr))
try:
return o[arg]
except IndexError:
return 0

@staticmethod
def make_puter(rdx, opr):
"""return a function based on pute."""
o = tuple(Logic.lsd(rdx, opr))
def puter(arg):
if arg < 0:
return 0
try:
return o[arg]
except IndexError:
return 0
return puter

@staticmethod
def make_inputs(rdx, *args):
"""yield a stripe of rdxn digits from args."""
largs = [Logic.lsd(rdx, a) for a in args]
for i in itertools.izip_longest(*largs, fillvalue=0):
yield Logic.rdxn(rdx, i)

@staticmethod
def compute(rdx, opr, *args):
"""return a number computed from opr of rdx."""
puter = Logic.make_puter(rdx, opr)
inputs = Logic.make_inputs(rdx, *args)
outputs = [puter(i) for i in inputs]
return Logic.rdxn(rdx, outputs)

@staticmethod
def make_computer(rdx, opr):
"""return a computer of opr, rdx."""
def computer(*args):
puter = Logic.make_puter(rdx, opr)
inputs = Logic.make_inputs(rdx, *args)
outputs = [puter(i) for i in inputs]
return Logic.rdxn(rdx, outputs)
return computer

def __init__(self, rdx, opr):
self._computer = Logic.make_computer(rdx, opr)

def __call__(self, *args):
return self._computer(*args)

This seemed to be working for the limited tests I did on it, while I
was doing them. The following checked out last time I tried:

I have no idea how to validate the results of the trinary and beyond
logics.

Thanks for reading and trying this out. Corrections? Criticism?
Comments?
 
S

Steven D'Aprano

I was staring at a logic table the other day, and I asked myself, "what
if one wanted to play with exotic logics; how might one do it?"


First question: what's an exotic logics?

Do you mean things like three-value logic, fuzzy logic, probabilistic
reasoning, etc?

Or do you mean logical operators others than and, or, xor, nand, nor, etc?

Or both? Something else?


I did
some searching but not being too sure of what to look for and carried
away with my own enthusiasm for the idea, I didn't find much. What I've
come up with is, no doubt, inefficient, naive, poor python style, and
probably wrong in fundamental ways too subtle for me, but here it is:

import itertools
import operator

class Logic():
"""class of generic logic operators"""
[...]

If (nearly) all your methods are static methods, chances are a class is
the wrong solution. Why not just define the static methods as top-level
functions?

This seemed to be working for the limited tests I did on it, while I was
doing them. The following checked out last time I tried:


I have no idea how to validate the results of the trinary and beyond
logics.

The same way you would validate and_, or_ and xor: to validate something,
you need to know what the correct answer is, then compare the answer you
get with the answer you should get. For a binary operator and binary
operands, you can exhaustively check every valid input:

flag1 op flag2

there are four combinations of input flags:

0 op 0
0 op 1
1 op 0
1 op 1

For three-valued logic, there are 9 combinations. For four-valued, 16. So
exhaustively testing all the possible inputs is quite simple.

As far as getting the correct answers, you have to decide which three-
valued logic(s) you want to use, then go look them up. Or just make them
up yourself!

E.g. given trinary flags 0, 1, 2, (say), you might want the operators to
give the same results with 0, 1 as they would if you were applying it to
binary flags 0, 1. E.g.:

# binary operands
0 and 0 => 0
0 and 1 => 0
1 and 0 => 0
1 and 1 => 1

# trinary operands

0 and 0 => 0
0 and 1 => 0
0 and 2 => ? # probably 0
1 and 0 => 0
1 and 1 => 1
1 and 2 => ? # could be 0, or maybe 1
2 and 0 => ? # probably 0
2 and 1 => ? # 0 or 1
2 and 2 => ? # probably 2

Different choices lead to different versions of ternary logic.



Thanks for reading and trying this out. Corrections? Criticism?
Comments?

You're implementation seems rather confusing. I think that's partly
because you use lots of abbreviated jargon terms that mean little or
nothing to me: rdx, opr (operator?), lsd, pute.
 
S

Steven D'Aprano

I was staring at a logic table the other day, and I asked myself, "what
if one wanted to play with exotic logics; how might one do it?"


This might be useful for you, and if not useful, at least it might blow
your mind like it did mine.

(This is not original to me -- I didn't create it. However, I can't find
the original source.)

Imagine for a moment that there are no boolean values.
There are no numbers. They were never invented.
There are no classes.
There are no objects.
There are only functions.

Could you define functions that act like boolean values? And could you
define other functions to operate on them?


def true(x, y):
return x

def false(x, y):
return y

def print_bool(b):
print b("true", "false")

print_bool(true)
print_bool(false)


def Not(b):
def not_b(x, y):
return b(y, x)
return not_b

print_bool(Not(true))
print_bool(Not(false))
print_bool(Not(Not(true)))

def And(a, b):
return a(b, a)

def Or(a, b):
return a(a, b)

print_bool(And(true, true))
print_bool(And(true, false))
print_bool(Or(false, true))
print_bool(Or(false, false))
 
L

Lie Ryan

Steven said:
This might be useful for you, and if not useful, at least it might blow
your mind like it did mine.

(This is not original to me -- I didn't create it. However, I can't find
the original source.)

Imagine for a moment that there are no boolean values.
There are no numbers. They were never invented.
There are no classes.
There are no objects.
There are only functions.

Could you define functions that act like boolean values? And could you
define other functions to operate on them?


def true(x, y):
return x

def false(x, y):
return y

def print_bool(b):
print b("true", "false")

String isn't considered object?

Also, b/true()/false() is a function object, isn't it? Unless function
is first-class, you can't pass them around like that, since you need a
function pointer (a.k.a number); but if function is first-class then
there it is an object.
 
A

Aaron Brady

This might be useful for you, and if not useful, at least it might blow
your mind like it did mine.

(This is not original to me -- I didn't create it. However, I can't find
the original source.)

Imagine for a moment that there are no boolean values.
There are no numbers.  They were never invented.
There are no classes.
There are no objects.
There are only functions.

Could you define functions that act like boolean values? And could you
define other functions to operate on them?
snip

I think high and low /voltages/, though continuous and approximate,
might satisfy this.

There are no such things as electrons, only variations in density of
the luminiferous ether.
 
A

Aaron Brady

First question: what's an exotic logics?

Do you mean things like three-value logic, fuzzy logic, probabilistic
reasoning, etc?

You (OP) may be interested in the definitions of the fuzzy operators:

and( x, y ) := min( x, y )
or( x, y ) := max( x, y )
not( x ) := 1 (one)- x
nand( x, y ) := not( and( x, y ) ) = 1- min( x, y )

Defining 'xor' as '( x or y ) and ( not( x and y ) )', we have:

xor( x, y ) := min( max( x, y ), 1- min( x, y ) )

However, defining 'xor' as '( x and not y ) or ( y and not x )', we
don't have:

xor( x, y ) := max( min( x, 1- y ), min( y, 1-x ) )

Good question.
 
P

pdpi

String isn't considered object?

Also, b/true()/false() is a function object, isn't it? Unless function
is first-class, you can't pass them around like that, since you need a
function pointer (a.k.a number); but if function is first-class then
there it is an object.

What Steven was doing was implementing some of the more basic stuff
from Lambda calculus in python. If you're implementing a different
system in an existing language, you'll need to use _some_ facilities
of the original language to interface with the outside world. Anyway,
here's a sample interactive session I just tried:
.... print stuff
........ stuff("abc")
....abc

functions are first-class citizens in python.
 
A

Aaron Brady

You (OP) may be interested in the definitions of the fuzzy operators:

and( x, y ) := min( x, y )
or( x, y ) := max( x, y )
not( x ) := 1 (one)- x
nand( x, y ) := not( and( x, y ) ) = 1- min( x, y )

Defining 'xor' as '( x or y ) and ( not( x and y ) )', we have:

xor( x, y ) := min( max( x, y ), 1- min( x, y ) )

However, defining 'xor' as '( x and not y ) or ( y and not x )', we
don't have:

xor( x, y ) := max( min( x, 1- y ), min( y, 1-x ) )

Corollary:

xor1( x, y ) === xor2( x, y ).

Non-exhaustive demonstration, excerpt:
.... return min( max( x, y ), 1- min( x, y ) )
........ return max( min( x, 1- y ), min( y, 1- x ) )
........ for j in range( 0, 11, 2 ):
.... print i, j, xor2( x, y )*10, ' ',
.... print

0 0 0.0 0 2 2.0 0 4 4.0 0 6 6.0 0 8 8.0
2 0 2.0 2 2 2.0 2 4 4.0 2 6 6.0 2 8 8.0
4 0 4.0 4 2 4.0 4 4 4.0 4 6 6.0 4 8 6.0
6 0 6.0 6 2 6.0 6 4 6.0 6 6 4.0 6 8 4.0
8 0 8.0 8 2 8.0 8 4 6.0 8 6 4.0 8 8 2.0
10 0 10.0 10 2 8.0 10 4 6.0 10 6 4.0 10 8 2.0

They appear to be equal.

I forgot to mention, fuzzy values take on values from the continuous
open or closed range 0 to 1.
 
M

Mensanator

snip

I think high and low /voltages/, though continuous and approximate,
might satisfy this.

There are no such things as electrons,

I've got a Tesla coil if you'd like to meet some electrons personally.
 
A

Aaron Brady

What Steven was doing was implementing some of the more basic stuff
from Lambda calculus in python. If you're implementing a different
system in an existing language, you'll need to use _some_ facilities
of the original language to interface with the outside world.

Sir! Entropy levels are approaching dangerously low levels. We don't
even have enough entropy to fi
 
A

Aaron Brady

I've got a Tesla coil if you'd like to meet some electrons personally.

The Wall Street Journal ran an article about Asian pleasure markets;
they provide a-- quote-- "perfectly reasonable professional option".
 
W

William Clifford

First question: what's an exotic logics?

Do you mean things like three-value logic, fuzzy logic, probabilistic
reasoning, etc?

Or do you mean logical operators others than and, or, xor, nand, nor, etc?

Or both? Something else?

The short answer is 'yes'.

Obviously, I don't know much about this stuff. I was looking a table
of different
operators and their truth values and saw that these were just
different ways of
reading and comparing numbers. I wrote this code to explore this idea
in a
general sense and see where it leads and learn something about
computers.
[...]

If (nearly) all your methods are static methods, chances are a class is
the wrong solution. Why not just define the static methods as top-level
functions?

That is exactly how they started. I wrapped them up in an class
because I
thought I might want to create a bunch of them for testing and
experimentation. I'm curious to see how combinations of functions give
the
same (or different) results. I've read one can do all of the 16
binary
operations with clever uses of NAND or NOR.

[SNIP]
You're implementation seems rather confusing. I think that's partly
because you use lots of abbreviated jargon terms that mean little or
nothing to me: rdx, opr (operator?), lsd, pute.

Sorry about the confusion. It's because I'm confused. I should check
out a book on the subject. Thanks for your help.
 
T

Terry Reedy

William said:
same (or different) results. I've read one can do all of the 16
binary
operations with clever uses of NAND or NOR.

The book Laws of Form, by Spencer-Brown' is based on that observation,
with nand/nor expanded to n-ary 'bag' functions (like sum() is).
I recommend it, especially if you can find it in a library.

tjr
 
L

Lie Ryan

pdpi said:
What Steven was doing was implementing some of the more basic stuff
from Lambda calculus in python. If you're implementing a different
system in an existing language, you'll need to use _some_ facilities
of the original language to interface with the outside world. Anyway,
here's a sample interactive session I just tried:

.... print stuff
....
.... stuff("abc")
....
abc

functions are first-class citizens in python.

I've just reread my sentence, and even I wouldn't have understood (or
would misunderstood) what I was talking about if it was worded like that.

What I meant was: if you can pass a function as an argument to another
function, that means either: 1) you must use function pointer (numbers)
or 2) function is a first-class object. Both violates the restriction
(no number and no object respectively).

Even after abandoning the semantics of functions in python, going to
function as in purely mathematical sense, I still am not convinced
(warning: I don't know lambda calculus, although I program in heavily
functional style).

PS: the string comment was meant to be a joke...
 
L

Luis Alberto Zarrabeitia Gomez

Quoting Lie Ryan said:
pdpi said:
Steven D'Aprano wrote:
On Tue, 16 Jun 2009 22:46:14 -0700, William Clifford wrote:
I was staring at a logic table the other day, and I asked myself, "what
if one wanted to play with exotic logics; how might one do it?"
This might be useful for you, and if not useful, at least it might blow
your mind like it did mine.
(This is not original to me -- I didn't create it. However, I can't find
the original source.)
Imagine for a moment that there are no boolean values.
There are no numbers. They were never invented.
There are no classes.
There are no objects.
There are only functions.
Could you define functions that act like boolean values? And could you
define other functions to operate on them?
[basic lambda calculus definitions]
[...]
What I meant was: if you can pass a function as an argument to another
function, that means either: 1) you must use function pointer (numbers)
or 2) function is a first-class object. Both violates the restriction
(no number and no object respectively).

Even after abandoning the semantics of functions in python, going to
function as in purely mathematical sense, I still am not convinced
(warning: I don't know lambda calculus, although I program in heavily
functional style).

You are confusing semantics with implementation. At some point, of course one
would need to use real object (at the lowest level, the computer I'm typing this
in is a physical object). But the interesting part is that you can define the
whole logic system using nothing but functions. You may need to implement it
using objects, or maybe you could devise a machine that will behave like that
using only sticks on the floor, but that doesn't matter. From the user's
perspective, there would be only functions: no strings, no objects, no numbers.

That reminds me of my last class (disclaimer: I teach discrete math). I told my
students "well, let's assume that numbers exist", and I wasn't making fun of
them... I found that topic easier to understand (computability, primitive
recursion) if one ignores the numbers, even if one obviously has to write them
somewhere at some point.
 
S

Steven D'Aprano

....
String isn't considered object?

<handwave/>

Given that the strings only exist inside one function specifically for
printing, I think we can ignore that. If you prefer, print_bool() could
look at the function names, that would work just as well. One way or the
other, we have to get human-readable names into the system *somehow*.

Also, b/true()/false() is a function object, isn't it? Unless function
is first-class, you can't pass them around like that, since you need a
function pointer (a.k.a number); but if function is first-class then
there it is an object.

That's an implementation detail. So long as you can pass around
functions, and return them, then it doesn't matter whether they are
implemented as objects or not.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top