Exemplo n.º 1
0
    def __init__(self, handler, rule_factory_cb=None):
        self._handler = handler
        self._knowledge_base = ruly.KnowledgeBase(*handler.rules)
        self._factory_cb = rule_factory_cb

        all_outputs = set(itertools.chain(*handler.dependencies.keys()))
        all_inputs = set(itertools.chain(*handler.dependencies.values()))
        self._inputs = all_inputs - all_outputs
Exemplo n.º 2
0
    def decide(self, inputs, decision):
        """Attempts to solve for decision based on given inputs. May create
        new rules if the factory creates them.

        Args:
            inputs (Dict[str, Any]): name-value pairs of all inputs
            decision (str): name of the decision that should be resolved

        Returns:
            Any: calculated decision

        Raises:
            ruly_dmn.HitPolicyViolation: raised if hit policy violation is
            detected"""
        rules = list(self._knowledge_base.rules)
        if self._factory_cb is None:
            rule_factory = _ConsoleRuleFactory(self._handler)
        else:
            rule_factory = self._factory_cb(self._handler)

        def post_eval_cb(state, output_name, fired_rules):
            fired_rules = _resolve_hit_policy(
                fired_rules, self._handler.hit_policies[output_name])
            new_rule = rule_factory.create_rule(state, fired_rules,
                                                output_name)
            if new_rule is not None and new_rule not in rules:
                if len(fired_rules) == 0:
                    rules.append(new_rule)
                else:
                    rules.insert(rules.index(fired_rules[0]), new_rule)
                raise _CancelEvaluationException()
            elif len(fired_rules) > 0:
                state = dict(state, **fired_rules[0].consequent)
            return state

        state = None
        rule_count = len(rules)
        rules_changed = False
        while state is None:
            try:
                state = ruly.backward_chain(self._knowledge_base,
                                            decision,
                                            post_eval_cb=post_eval_cb,
                                            **inputs)
            except _CancelEvaluationException:
                if len(rules) == rule_count:
                    break
                else:
                    rules_changed = True
                    self._knowledge_base = ruly.KnowledgeBase(*rules)

        if rules_changed:
            self._handler.update(self._knowledge_base)

        return state[decision]
Exemplo n.º 3
0
def test_backward_chain():
    kb = ruly.KnowledgeBase(
        'IF sound="croak" AND behavior="eats flies" THEN animal="frog"',
        'IF sound="chirp" AND behavior="sings" THEN animal="canary"',
        'IF animal="frog" THEN color="green"',
        'IF animal="canary" THEN color="yellow"')

    state = ruly.backward_chain(kb,
                                'color',
                                sound='croak',
                                behavior='eats flies')
    assert state['color'] == 'green'

    state = ruly.backward_chain(kb, 'color', sound='chirp', behavior='sings')
    assert state['color'] == 'yellow'
Exemplo n.º 4
0
def test_numeric():
    kb = ruly.KnowledgeBase(
        'IF weight>=100 THEN animal="elephant"',
        'IF weight>=50 AND weight<100 THEN animal="horse"',
        'IF weight>=25 AND weight<50 THEN animal="dog"',
        'IF weight>0 AND weight<25 THEN animal="mouse"')

    state = ruly.backward_chain(kb, 'animal', weight=145)
    assert state['animal'] == 'elephant'

    state = ruly.backward_chain(kb, 'animal', weight=59)
    assert state['animal'] == 'horse'

    state = ruly.backward_chain(kb, 'animal', weight=37)
    assert state['animal'] == 'dog'

    state = ruly.backward_chain(kb, 'animal', weight=12)
    assert state['animal'] == 'mouse'
Exemplo n.º 5
0
def test_bc_post_eval():
    kb = ruly.KnowledgeBase(
        'IF sound="croak" AND behavior="eats flies" THEN animal="frog"',
        'IF sound="chirp" THEN animal="bird"',
        'IF sound="chirp" AND behavior="sings" THEN animal="canary"',
        'IF animal="frog" THEN color="green"',
        'IF animal="canary" THEN color="yellow"',
        'IF animal="bird" THEN color="n/a"')

    def post_eval_cb(state, output_name, fired_rules):
        if len(fired_rules) == 0:
            return dict(state, **{output_name: 'really n/a'})
        elif len(fired_rules) == 1:
            selected_rule = fired_rules[0]
        else:
            selected_rule = max(
                fired_rules,
                key=lambda r: len(ruly.get_rule_depending_variables(r)))
        new_state = dict(state)
        new_state.update(selected_rule.consequent)
        return new_state

    state = ruly.backward_chain(kb,
                                'color',
                                post_eval_cb=post_eval_cb,
                                sound='chirp',
                                behavior='sings')
    assert state['color'] == 'yellow'

    state = ruly.backward_chain(kb,
                                'color',
                                post_eval_cb=post_eval_cb,
                                sound='chirp')
    assert state['color'] == 'n/a'

    state = ruly.backward_chain(kb,
                                'color',
                                post_eval_cb=post_eval_cb,
                                sound='roar')
    assert state['color'] == 'really n/a'
Exemplo n.º 6
0
def test_knowledge_base_parses():
    rule_str = 'IF rule_engine="ruly" THEN usability="awesome"'
    rule = ruly.parse(rule_str)
    knowledge_base = ruly.KnowledgeBase(rule_str)
    assert knowledge_base.rules == (rule, )