python-3.x 如何从experta库的规则引擎中提取规则

brccelvz  于 2023-03-24  发布在  Python
关注(0)|答案(1)|浏览(209)

我试图从我使用experta库构建的规则引擎中提取规则。
下面是代码

from experta import *
import pydot

class Iris(Fact):
    """IRIS"""
    sepal_length = Field(float)
    sepal_width = Field(float)
    petal_length = Field(float)
    petal_width = Field(float)

class Species(Fact):
    """Species characteristics"""
    pass

class IrisExpert(KnowledgeEngine):

    def __init__(self):
        super().__init__()
        self.status = None

    @Rule(Iris(sepal_length=P(lambda x: x > 5), sepal_width=P(lambda x: x < 3)))
    def rule1(self):
        self.status = 'Iris Setosa'
        return self.declare(Species(flower='Iris Setosa'))

    @Rule(AND(
        Iris(sepal_length=P(lambda x: x > 5.5)),
        Iris(sepal_width=P(lambda x: x > 2.5))
    ))
    def rule2(self):
        self.status = 'Iris Versicolor'
        return self.declare(Species(flower='Iris Versicolor'))

    @Rule(AND(
        Iris(petal_length=P(lambda x: x > 4.8)),
        Iris(petal_width=P(lambda x: x > 1.8))
    ))
    def rule3(self):
        self.status = 'Iris Virginica'
        return self.declare(Species(flower='Iris Virginica'))

def execute_fuc(key):
    if key == 'rule1':
        print('executing rule-1')
        engine.rule1()
    elif key == 'rule2':
        print('executing rule-2')
        engine.rule2()
    else:
        print('executing rule-3')
        engine.rule3()

# Create a new knowledge engine instance
engine = IrisExpert()
engine.reset()
# Create a Pydot graph
graph = pydot.Dot(graph_type='digraph', comment='IRIS Expert Rules')
# Add nodes for each rule
for rule_instance in engine.get_rules():
    quality = rule_instance()
    qual_node = pydot.Node(repr(quality))
    graph.add_node(qual_node)
    for rule in rule_instance:
        print('rule_format: ',repr(rule))

我得到了以下格式

rule_format: Iris(petal_width=P(<function IrisExpert.<lambda> at 0x7fe3fd4788c8>,))

但我想找的是

Iris(petal_width=P(<function IrisExpert. x > 5)) (for function "rule1")
kadbb459

kadbb4591#

你显然是想重写lambda函数的repr方法。This answer展示了如何做到这一点。应用到你的案例(两种< and >表示),你可以做以下事情:

from experta import *
import pydot
import functools

class reprwrapper(object):
    def __init__(self, repr, func):
        self._repr = repr
        self._func = func
        functools.update_wrapper(self, func)
    def __call__(self, *args, **kw):
        return self._func(*args, **kw)
    def __repr__(self):
        return self._repr(self._func)

def withrepr(reprfun):
    def _wrap(func):
        return reprwrapper(reprfun, func)
    return _wrap

def x_gt(a):
    @withrepr(lambda x: f"function IrisExpert. x > {a}")
    def gt_a(x):
        return x > a
    return gt_a

def x_lt(a):
    @withrepr(lambda x: f"function IrisExpert. x < {a}")
    def lt_a(x):
        return x < a
    return lt_a

class Iris(Fact):
    """IRIS"""
    sepal_length = Field(float)
    sepal_width = Field(float)
    petal_length = Field(float)
    petal_width = Field(float)

class Species(Fact):
    """Species characteristics"""
    pass

class IrisExpert(KnowledgeEngine):

    def __init__(self):
        super().__init__()
        self.status = None

    @Rule(Iris(sepal_length=P(x_gt(5)), sepal_width=P(x_lt(3))))
    def rule1(self):
        self.status = 'Iris Setosa'
        return self.declare(Species(flower='Iris Setosa'))

    @Rule(AND(
        Iris(sepal_length=P(x_gt(5.5))),
        Iris(sepal_width=P(x_gt(2.5)))
    ))
    def rule2(self):
        self.status = 'Iris Versicolor'
        return self.declare(Species(flower='Iris Versicolor'))

    @Rule(AND(
        Iris(petal_length=P(x_gt(4.8))),
        Iris(petal_width=P(x_gt(1.8)))
    ))
    def rule3(self):
        self.status = 'Iris Virginica'
        return self.declare(Species(flower='Iris Virginica'))

def execute_fuc(key):
    if key == 'rule1':
        print('executing rule-1')
        engine.rule1()
    elif key == 'rule2':
        print('executing rule-2')
        engine.rule2()
    else:
        print('executing rule-3')
        engine.rule3()

# Create a new knowledge engine instance
engine = IrisExpert()
engine.reset()
# Create a Pydot graph
graph = pydot.Dot(graph_type='digraph', comment='IRIS Expert Rules')
# Add nodes for each rule
for rule_instance in engine.get_rules():
    quality = rule_instance()
    qual_node = pydot.Node(repr(quality))
    graph.add_node(qual_node)
    for rule in rule_instance:
        print('rule_format: ',repr(rule))

输出:

rule_format:  Iris(sepal_length=P(function IrisExpert. x > 5,), sepal_width=P(function IrisExpert. x < 3,))
rule_format:  AND(Iris(sepal_length=P(function IrisExpert. x > 5.5,)), Iris(sepal_width=P(function IrisExpert. x > 2.5,)))
rule_format:  AND(Iris(petal_length=P(function IrisExpert. x > 4.8,)), Iris(petal_width=P(function IrisExpert. x > 1.8,)))

相关问题