Skip to content

Commit

Permalink
An initial forray into backward chaining.
Browse files Browse the repository at this point in the history
Implements BackwardFilterNode and BackwardExtremumNode.

No thought has yet been put into integrating these with the @rule
macro.  For now, such nodes will need tto be created and connected by
hand.
  • Loading branch information
MarkNahabedian committed Mar 26, 2024
1 parent 18e85a9 commit 32d3d3e
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
Rete is a simple library for implementing rule based systems using the
Rete algorithm.

Only forward chaining is supported.
Rete currently implements memory for Julia types, forward chaining
joins, and backward chaining filter and extrema operations.

See the documentation linked above.

Expand Down
1 change: 1 addition & 0 deletions src/Rete.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ include("node_abstraction.jl")
include("basic_node.jl")
include("memory_nodes.jl")
include("join_nodes.jl")
include("backward.jl")
include("rules.jl")
include("utils.jl")

Expand Down
83 changes: 83 additions & 0 deletions src/backward.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Some backwad chaining functionality

export BackwardChaining, BackwardFilterNode, BackwardExtremumNode


"""
BackwardChaining is the abstract supertype for all backward chaining
Rete nodes.
"""
abstract type BackwardChaining <: AbstractReteNode end


function receive(::BackwardChaining, fact)
# no-op
end


"""
BackwardFilterNode(filter_function, label)
When `askc`ed, passes through from its inputs only those facts whuich
satisfy `predicate`.
"""
struct BackwardFilterNode <: BackwardChaining
inputs::Set{AbstractReteNode}
outputs::Set{AbstractReteNode}
predicate
label

function BackwardFilterNode(predicate, label)
new(Set{AbstractReteNode}(),
Set{AbstractReteNode}(),
predicate, label)
end
end

function askc(continuation, node::BackwardFilterNode)
for input in node.inputs
askc(input) do fact
if node.predicate(fact)
continuation(fact)
end
end
end
end



"""
BackwardExtremumNode(comparison, extractor, label)
When `askc`ed, provides one value: the fact with the most extreme
value (based on `comparison`) of `extractor` applied to each input
fact at the time `askc` was called.
"""
struct BackwardExtremumNode <: BackwardChaining
inputs::Set{AbstractReteNode}
outputs::Set{AbstractReteNode}
comparison
extractor
label

function BackwardExtremumNode(comparison, extractor, label)
new(Set{AbstractReteNode}(),
Set{AbstractReteNode}(),
comparison, extractor, label)
end
end

function askc(continuation, node::BackwardExtremumNode)
extremum = nothing
for input in node.inputs
askc(input) do fact
if extremum === nothing || node.comparison(node.extractor(fact),
extremum)
extremum = fact
end
end
end
continuation(extremum)
end

1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ end
@test length(root.outputs) == 1
end

include("test_backwards.jl")
include("rule_example_2.jl")
include("rule_grouping.jl")
include("three_parameter_rule_example.jl")
Expand Down
31 changes: 31 additions & 0 deletions test/test_backwards.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

@testset "test BackwardFilterNode" begin
root = ReteRootNode("root")
ints = ensure_IsaMemoryNode(root, Int)
connect(root, ints)
even = BackwardFilterNode(iseven, "even Ints")
connect(ints, even)
for i in 1:10
receive(root, i)
end
filtered = collecting() do c
askc(c, even)
end
@test sort(filtered) == [2, 4, 6, 8, 10]
end

@testset "test BackwardExtremumNode" begin
root = ReteRootNode("root")
ints = ensure_IsaMemoryNode(root, Int)
connect(root, ints)
maxval = BackwardExtremumNode(>, identity, "greatest int")
connect(ints, maxval)
for i in 1:10
receive(root, i)
end
extreme = collecting() do c
askc(c, maxval)
end
@test extreme == [10]
end

0 comments on commit 32d3d3e

Please sign in to comment.