Skip to content

Commit

Permalink
Merge branch 'hotfix-1.0.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
nilp0inter committed Apr 6, 2017
2 parents d0e681a + 9bf2f0d commit 0a15d1b
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 9 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
1.0.1
+++++

* DNF of OR clause inside AND or Rule was implemented wrong.


1.0.0
+++++

Expand All @@ -6,6 +12,7 @@
* Facts are dictionaries.
* Documentation.


<1.0.0
++++++

Expand Down
11 changes: 5 additions & 6 deletions pyknow/matchers/rete/dnf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def dnf(exp):

@dnf.register(Rule)
def _(exp):
last, current = None, exp.new_conditions(*[dnf(e) for e in exp])
last, current = None, exp.new_conditions(AND(*[dnf(e) for e in exp]))

while last != current:
last, current = (current,
Expand Down Expand Up @@ -61,14 +61,13 @@ def _(exp):
if len(exp) == 1:
return dnf(exp[0])
elif any(isinstance(e, OR) for e in exp): # Distributive property
and_part = []
or_part = []
parts = []
for e in exp:
if isinstance(e, OR):
or_part.extend(e)
parts.append([dnf(x) for x in e])
else:
and_part.append(e)
return OR(*[dnf(AND(*(and_part + [dnf(e)]))) for e in or_part])
parts.append([dnf(e)])
return OR(*[dnf(AND(*p)) for p in product(*parts)])
else:
return AND(*[dnf(x) for x in unpack_exp(exp, AND)])

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
README = open(os.path.join(HERE, 'README.rst')).read()
NEWS = open(os.path.join(HERE, 'TODO.rst')).read()

VERSION = '1.0.0'
VERSION = '1.0.1'

setup(name='pyknow',
version=VERSION,
Expand Down
47 changes: 47 additions & 0 deletions tests/unit/matchers/rete/test_constructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,50 @@ def r1(self):

ke.retract(f4)
assert not ke.agenda.activations


def test_OR_inside_Rule():
from pyknow import KnowledgeEngine, OR, Fact, Rule

class KE(KnowledgeEngine):
@Rule(Fact(1),
OR(Fact('a'),
Fact('b')),
OR(Fact('x'),
Fact('y')))
def r1(self):
pass

ke = KE()
ke.reset()
assert len(ke.agenda.activations) == 0

p0 = ke.declare(Fact(1))
assert len(ke.agenda.activations) == 0

p1 = ke.declare(Fact('a'))
assert len(ke.agenda.activations) == 0

p2 = ke.declare(Fact('x'))
assert len(ke.agenda.activations) == 1

ke.retract(p2)
assert len(ke.agenda.activations) == 0

p2 = ke.declare(Fact('y'))
assert len(ke.agenda.activations) == 1

ke.retract(p1)
assert len(ke.agenda.activations) == 0

p1 = ke.declare(Fact('b'))
assert len(ke.agenda.activations) == 1

ke.retract(p2)
assert len(ke.agenda.activations) == 0

p2 = ke.declare(Fact('x'))
assert len(ke.agenda.activations) == 1

ke.retract(p0)
assert len(ke.agenda.activations) == 0
21 changes: 19 additions & 2 deletions tests/unit/matchers/rete/test_dnf.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
"""
Tests on Rule DNF
"""

# pylint: disable=missing-docstring
import pytest


def test_or_inside_and():
Expand Down Expand Up @@ -185,3 +184,21 @@ def test_and_inside_or_inside_fact():

result = dnf(input_)
assert result == output


def test_multiple_or_inside_rule():
from pyknow import Fact, OR, Rule, AND
from pyknow.matchers.rete.dnf import dnf

input_ = Rule(Fact(a=1),
OR(Fact(b=1),
Fact(b=2)),
OR(Fact(c=1),
Fact(c=2)))
output_ = Rule(OR(AND(Fact(a=1), Fact(b=1), Fact(c=1)),
AND(Fact(a=1), Fact(b=1), Fact(c=2)),
AND(Fact(a=1), Fact(b=2), Fact(c=1)),
AND(Fact(a=1), Fact(b=2), Fact(c=2))))

result = dnf(input_)
assert result == output_

0 comments on commit 0a15d1b

Please sign in to comment.