I've decided to implement a Python library for existing a.i. techniques while I am working on my theory of intelligence.
It may happen that my theory will incorporate some of the techniques, and even if it does not I will at least have proof positive that I understand them. I will also release my library. Hopefully we will see more people involved in implementing a.i. theories and applications.
I'm starting off with fuzzy logic.
http://en.wikipedia.org/wiki/Fuzzy_logicAt the moment I have implemented fuzzy sets, but I still need to implement fuzzy linguistic variables, advanced inference, defuzzification, and the Combs method.
It's possible to create a fuzzy set from a membership function, get elements' memberships in the set, get the complement of the set, the intersection of sets, the union of sets, modify the set, and the implication of two sets.
P.S. I have all ready thought of a potential refactoring that may increase flexibility. Software development (especially my software development
) is an iterative process of refinement.
Existing Python 3.1 code:
# encoding: utf-8
##The MIT License
##
##Copyright (c) 2011 Larry Haskins
##
##Permission is hereby granted, free of charge, to any person obtaining a copy
##of this software and associated documentation files (the "Software"), to deal
##in the Software without restriction, including without limitation the rights
##to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
##copies of the Software, and to permit persons to whom the Software is
##furnished to do so, subject to the following conditions:
##
##The above copyright notice and this permission notice shall be included in
##all copies or substantial portions of the Software.
##
##THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
##IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
##FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
##AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
##LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
##OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
##THE SOFTWARE.
"""A module for fuzzification, defuzzification, and fuzzy knowledge
categorization, representation, and decision making."""
import math
import weakref
__author__ = "Larry Haskins"
__version__ = "1.0"
__all__ = ['never',
'very',
'extremely',
'more_or_less',
'slightly',
'FuzzySet',
'nothing',
'everything',
'always']
#TODO: Refactor sufficiently similar code to functions.
def never(element):
"""Special case membership function.
Only fuzzy sets with this membership function are empty.
"""
return 0
#COMMON MODIFIER FUNCTIONS
def very(value):
return value ** 2
def extremely(value):
return value ** 3
def more_or_less(value):
return math.sqrt(value)
def slightly(value):
return value ** (1/3)
#END COMMON MODIFIER FUNCTIONS
class FuzzySet(object):
"""Represents the mapping of items in the universe to their degree of
membership in the set."""
#NOTE: Fuzzy set theory differs from classical (or Boolean) set theory.
_complement_functions = weakref.WeakValueDictionary()
_intersection_functions = weakref.WeakValueDictionary()
_union_functions = weakref.WeakValueDictionary()
_modifier_functions = weakref.WeakValueDictionary()
_implication_functions = weakref.WeakValueDictionary()
def __init__(self, membership_function):
"""The membership function calculates an element's degree of membership
in this set.
Membership functions must always return a value on the
interval [0, 1], with 0 meaning the element is not in the set, and 1
meaning the element is fully in the set. Intermediate values indicate
partial membership.
"""
super(FuzzySet, self).__init__()
self._membership_function = membership_function
@property
def membership_function(self):
return self._membership_function
def complement(self):
"""Returns the complement set.
Conceptually, the complement is the logical opposite of the original.
If an element has a high degree of membership in the original, it will
have a low degree of membership in the complement. If an element has a
low degree of membership in the original, it will have a high degree of
membership in the complement.
Note: The complement of a complement is equal to the original.
"""
cls = self.__class__
membership_function = self._membership_function
try:
complement_function = cls._complement_functions[membership_function]
except KeyError:
def complement_function(element):
return 1 - membership_function(element)
cls._complement_functions.update({membership_function: complement_function,
complement_function: membership_function})
return cls(complement_function)
def __hash__(self):
return hash(self._membership_function)
def __getitem__(self, element):
return self._membership_function(element)
def __eq__(self, other):
"""Two sets are equal if and only if the two membership functions are
the same for all elements in both.
It is impossible to check all
elements. Checking a finite collection of elements is incorrect. The
membership functions may differ for elements not explicitly checked.
ATTENTION: If you know a better way to compare functions please inform
me.
"""
return self._membership_function == other._membership_function
def __bool__(self):
"""A set is empty if and only if the membership value is always 0."""
return self._membership_function != never
def intersection(self, *others):
"""Returns the intersection of this set and the others.
The intersection returns the minimum of all membership functions for
any given element. Conceptually, the intersection is like the English
word "and". If an element has a high degree of membership in one set
"and" the others, it will have a high degree of membership in the
intersection.
"""
cls = self.__class__
participants = set(others)
participants.add(self)
membership_functions = frozenset(participant._membership_function for participant in participants)
try:
intersection_function = cls._intersection_functions[membership_functions]
except KeyError:
def intersection_function(element):
return min(membership_function(element) for membership_function in membership_functions)
cls._intersection_functions[membership_functions] = intersection_function
return cls(intersection_function)
def union(self, *others):
"""Returns the union of this set and the others.
The union returns the maximum of all membership functions for any given
element. Conceptually, the union is like the English word "or". If an
element has a high degree of membership in one set "or" the others, it
will have a high degree of membership in the union.
"""
cls = self.__class__
participants = set(others)
participants.add(self)
membership_functions = frozenset(participant._membership_function for participant in participants)
try:
union_function = cls._union_functions[membership_functions]
except KeyError:
def union_function(element):
return max(membership_function(element) for membership_function in membership_functions)
cls._union_functions[membership_functions] = union_function
return cls(union_function)
def modify(self, modifier_function):
"""Returns the modification of this set.
A modifier changes an element's degree of membership in the modified
set.
Note: A programmer or knowledge engineer must implement the modifier.
This merely returns the set that applies the modifier.
"""
cls = self.__class__
membership_function = self._membership_function
key = (membership_function, modifier_function)
try:
modified_function = cls._modifier_functions[key]
except KeyError:
def modified_function(element):
return modifier_function(membership_function(element))
cls._modifier_functions[key] = modified_function
return cls(modified_function)
def implies(self, other):
"""Returns the implication between this set and the other.
Conceptually, an implication is a link. An element's degree of
membership in one set may be low, but if its membership in the other is
sufficiently high the implication will recognize the link.
Note: Implication is commutative. If one set implies another, the other
implies it. In real life implication may not always be commutative (at
least to the same degree). Take this with a grain of salt.
"""
cls = self.__class__
key = frozenset((self._membership_function, other._membership_function))
try:
implication_function = cls._implication_functions[key]
except KeyError:
def implication_function(element):
return max((0, self._membership_function(element) + other._membership_function(element) - 1))
cls._implication_functions[key] = implication_function
return cls(implication_function)
def fuzzify(self, *elements):
"""Returns the mapping of elements to their degree of membership in
this set."""
return dict((element, self._membership_function(element)) for element in elements)
nothing = FuzzySet(never)
everything = nothing.complement()
always = everything.membership_function #opposite of never
if __name__ == '__main__':
pass