""" AND, NOT and OR operators for fuzzy logic inference systems """
# pylint: disable=invalid-name, R0903
from typing import Union, Dict, cast
import numpy as np
from .kernel import Kernel
from .operators import OperatorEnum
[docs]class Rules:
"""Rules MetaClass"""
[docs]class RuleBase(Rules):
"""Base class for all declarative rules"""
[docs] def __init__(self, operand_set: OperatorEnum, a, b=None) -> None:
if operand_set is not None and not isinstance(operand_set, OperatorEnum):
raise TypeError(f"Expected type OperatorEnum for 'operand'. Got {type(operand_set)}")
self.operand_set = operand_set
self.a = a
self.b = b
def __call__(self, input_kernel_membership) -> np.ndarray:
pass
def _resolve(x: Union[Rules, Dict[str, str]], input_kernel_set: Dict[str, Kernel]) -> np.ndarray:
if isinstance(x, RuleBase):
return x(input_kernel_set)
assert len(x) == 1
x = cast(dict, x)
variable = list(x.keys())[0]
membership_val = x.get(variable)
if variable in input_kernel_set.keys():
return input_kernel_set[variable].membership_degree[membership_val]
raise KeyError(f"Cannot find kernel named '{variable}' in the kernel set")
[docs]class AND(RuleBase):
"""AND Operator. Performs the AND function as defined by the OperatorEnum of choice"""
[docs] def __init__(
self,
a: Union[RuleBase, Dict[str, str]],
b: Union[RuleBase, Dict[str, str]],
operand_set: OperatorEnum = None,
) -> float:
super().__init__(operand_set, a, b)
def __call__(self, input_kernel_membership) -> np.ndarray:
a = _resolve(self.a, input_kernel_membership)
b = _resolve(self.b, input_kernel_membership)
func = self.operand_set.value[0]
# print("AND:", a, b, "->", func(a, b))
return func(a, b)
[docs]class OR(RuleBase):
"""OR Operator. Performs the OR function as defined by the OperatorEnum of choice"""
[docs] def __init__(
self,
a: Union[RuleBase, Dict[str, str]],
b: Union[RuleBase, Dict[str, str]],
operand_set: OperatorEnum = None,
) -> float:
super().__init__(operand_set, a, b)
def __call__(self, input_kernel_membership) -> np.ndarray:
a = _resolve(self.a, input_kernel_membership)
b = _resolve(self.b, input_kernel_membership)
func = self.operand_set.value[1]
# print("OR:", a, b, "->", func(a, b))
return func(a, b)
[docs]class NOT(RuleBase):
"""NOT Operator. Performs the NOT function as defined by the OperatorEnum of choice"""
[docs] def __init__(
self, a: Union[RuleBase, Dict[str, str]], operand_set: OperatorEnum = None
) -> float:
super().__init__(operand_set, a)
def __call__(self, input_kernel_set) -> np.ndarray:
a = _resolve(self.a, input_kernel_set)
func = self.operand_set.value[2]
# print("NOT:", a, "->", func(a))
return func(a)
[docs]class IS(RuleBase):
"""IS Operator. Performs the IS function as defined by the OperatorEnum of choice"""
[docs] def __init__(
self, a: Union[RuleBase, Dict[str, str]], operand_set: OperatorEnum = None
) -> float:
super().__init__(operand_set, a)
def __call__(self, input_kernel_set) -> np.ndarray:
a = _resolve(self.a, input_kernel_set)
func = self.operand_set.value[3]
# print("IS:", a, "->", func(a))
return func(a)