0

I would like to generate a flow using the rules that I defined in the rules engine. Below is the code

from pyknow import *
import pydot

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

class Quality(Fact):
    """Wine quality"""
    pass

class WineExpert(KnowledgeEngine):
    @Rule(Wine(color='red'))
    def rule1(self):
        self.declare(Quality(color='red', quality='rich'))

    @Rule(Wine(color='white'))
    def rule2(self):
        self.declare(Quality(color='white', quality='crisp'))

    @Rule(AND(
        Wine(color='red'),
        Wine(body='light'),
        Wine(tannin='low')
    ))
    def rule3(self):
        self.declare(Quality(color='red', quality='smooth'))

    @Rule(AND(
        Wine(color='red'),
        Wine(body='full'),
        Wine(tannin='high')
    ))
    def rule4(self):
        self.declare(Quality(color='red', quality='bold'))

# Create a new knowledge engine instance
engine = WineExpert()

# Create a Pydot graph
graph = pydot.Dot(graph_type='digraph', comment='Wine Expert Rules')

# Add nodes for each rule
for rule in engine.get_rules():
    node = pydot.Node(rule.__name__)
    graph.add_node(node)

    # Check for AND conditions
    if isinstance(rule.new_conditions, AND):
        for condition in rule.new_conditions.args:
            label = str(condition).replace("<", "\\<").replace(">", "\\>")
            edge = pydot.Edge(label, rule.__name__)
            graph.add_edge(edge)
    else:
        label = str(rule.new_conditions).replace("<", "\\<").replace(">", "\\>")
        edge = pydot.Edge(label, rule.__name__)
        graph.add_edge(edge)

# Save the graph to a file
graph.write_png('wine_expert_rules.png')

I am getting a graph which I can't interpret it. Can anyone tell me how to get a good flowchart out of it?

Tranbi
  • 11,407
  • 6
  • 16
  • 33
merkle
  • 1,585
  • 4
  • 18
  • 33

1 Answers1

1

There seems to be a some confusion with decorators and classes. Also you never execute the rule. Do you expect quality to appear on your flow chart? If so, you should run the rules in your loop. Note: I'm also returning Quality to avoid accessing the engine's agenda and drawing AND nodes (also using experta which is a fork and available at pypi):

from experta import *
import pydot

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

class Quality(Fact):
    """Wine quality"""
    pass

class WineExpert(KnowledgeEngine):
    @Rule(Wine(color='red'))
    def rule1(self):
        return self.declare(Quality(color='red', quality='rich'))

    @Rule(Wine(color='white'))
    def rule2(self):
        return self.declare(Quality(color='white', quality='crisp'))

    @Rule(AND(
        Wine(color='red'),
        Wine(body='light'),
        Wine(tannin='low')
    ))
    def rule3(self):
        return self.declare(Quality(color='red', quality='smooth'))

    @Rule(AND(
        Wine(color='red'),
        Wine(body='full'),
        Wine(tannin='high')
    ))
    def rule4(self):
        return self.declare(Quality(color='red', quality='bold'))

# Create a new knowledge engine instance
engine = WineExpert()
engine.reset()
# Create a Pydot graph
graph = pydot.Dot(graph_type='digraph', comment='Wine Expert Rules')

and_counter = 0
# 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:
        # Check for AND conditions
        if isinstance(rule, AND):
            and_node = pydot.Node(name=and_counter, label='AND')
            graph.add_node(and_node)
            and_counter += 1
            for condition in rule:
                cond_node = pydot.Node(repr(condition))
                graph.add_node(cond_node)
                edge = pydot.Edge(cond_node, and_node)
                graph.add_edge(edge)
            edge = pydot.Edge(and_node, qual_node)
            graph.add_edge(edge)
        else:
            cond_node = pydot.Node(repr(rule))
            graph.add_node(cond_node)
            edge = pydot.Edge(cond_node, qual_node)
            graph.add_edge(edge)

# Save the graph to a file
graph.write_png('wine_expert_rules.png')

Output:

enter image description here

Tranbi
  • 11,407
  • 6
  • 16
  • 33
  • How to highlight the path that user has chosen? – merkle Mar 10 '23 at 13:06
  • This is a completely different question. The user hasn't chosen anything in this example. Once the graph is compiled, reset your engine and run it again with the user inputs. – Tranbi Mar 10 '23 at 13:17
  • How to pass the input to the class? For example, the AND condition rule to the engine – merkle Mar 12 '23 at 03:14
  • I am passing as engine.declare(Wine(color=='red')) and then printing "engine.facts" but it is not working – merkle Mar 12 '23 at 04:48
  • `engine.declare(Wine(color='red'))` works (only one `=`) but will add a `Wine` object to the facts. It seems to defeat the purpose of your rules... Just run `engine.rule1()`. I suggest you read about [decorators](https://wiki.python.org/moin/PythonDecorators) – Tranbi Mar 12 '23 at 08:00