View difference between Paste ID: G9QhADgm and 5g3fjeN0
SHOW: | | - or go back to the newest paste.
1-
;; Backward Chaining
1+
%% Backward chaining
2
3-
(ns backward)
3+
-module(backward).
4-
(import '(java.util.concurrent Executors ExecutorCompletionService))
4+
-export([start/0,mainLoop/0,solveGoal/2,solveRule/2,collect/3]).
5
6-
(declare start solve-goal solve-rule collect unify)
6+
start() ->
7
	%% Initialize KB
8-
; Choose between using parallel collect or sequential collect.
8+
	ets:new(rules, [bag, named_table]),
9-
(def use-parallel-collect true)
9+
	ets:insert(rules, {g,[d,e,f,h,i,j],1.0}),
10
	ets:insert(rules, {g,[a,b,c],1.1}),
11-
(def completion-service (ExecutorCompletionService.
11+
	ets:insert(rules, {a,[],0.1}),
12-
	(Executors/newCachedThreadPool)))
12+
	ets:insert(rules, {b,[],0.2}),
13
	ets:insert(rules, {c,[],0.3}),
14-
(defn start []
14+
	ets:insert(rules, {d,[],0.4}),
15-
	(loop []
15+
	ets:insert(rules, {e,[],0.5}),
16-
		(print "Enter query: ") (flush)
16+
	ets:insert(rules, {f,[],0.6}),
17-
		(let [query (read-line)
17+
	ets:insert(rules, {h,[],0.7}),
18-
			truth (solve-goal (symbol query))]
18+
	ets:insert(rules, {i,[],0.8}),
19-
			(printf "Answer is: %s\n" truth))
19+
	ets:insert(rules, {j,[],0.9}),
20-
		(recur)))
20+
	mainLoop().
21
22-
(defn fetch-rules [goal]
22+
mainLoop() ->
23-
	(case goal
23+
	Query = io:read("Enter query: "),
24-
		g '[[a,b,c],[d,e,f]]
24+
	solveGoal(element(2, Query), self()),
25-
		a '[[e,f]]
25+
	receive
26-
		b '[[c,d,e,f]]
26+
		{_, Truth} -> io:format("Answer is: ~w~n", [Truth])
27-
		c '[[e,f]]
27+
	end,
28-
		d '[[e,f]]
28+
	mainLoop().
29-
		e '[[]]
29+
30-
		f '[[]]
30+
solveGoal(Goal, Caller) ->
31-
		true (throw (Exception. "No applicable rule"))))
31+
    %% Fetch rules...
32
	ApplicableRules = ets:match(rules,{Goal, '$1', '$2'}),
33-
(defn solve-goal [goal]
33+
	lists:foreach(
34-
	(let [rules (fetch-rules goal)]
34+
		fun([RuleBody,Truth]) ->
35-
		(if (some empty? rules)
35+
		if 
36-
			1.0		; return a truth value
36+
			%% If RHS is null
37-
			(do
37+
			RuleBody == [] -> Caller ! {Goal, Truth};
38-
				(doseq [rule rules]
38+
			%% If RHS contains subgoals
39-
					(.submit completion-service #(solve-rule rule)))
39+
			true -> spawn(backward, solveRule, [RuleBody, self()])
40-
				(.get (.take completion-service))))))
40+
		end end,
41
		ApplicableRules),
42-
; Move minimization logic here from collect.
42+
	receive
43-
(defn solve-rule [rule-tail]
43+
		%% Each message is of the form {goal,truth}
44-
	(let [truths (collect solve-goal rule-tail)]
44+
		%% Just accept the 1st answer
45-
		(apply + truths)))
45+
		{_, Truth} -> Caller ! {Goal, Truth}
46
	end.
47-
; Accumulate results
47+
48-
(def collect (if use-parallel-collect pmap map))
48+
solveRule(RuleTail, Caller) ->
49
	N = length(RuleTail),
50
	Collector = spawn(backward, collect, [[], N, Caller]),
51
	%% For each subgoal in Rule
52
	%% Spawn a process to solve each subgoal
53
	lists:foreach(
54
		fun(Subgoal) -> spawn(backward, solveGoal, [Subgoal, Collector]) end,
55
		RuleTail).
56
57
%% Accumulate results
58
collect(Truths, N, Caller) ->
59
	%% If we have N messages send back the answer
60
	%% Answer = min of truth values, equivalent to fuzzy-logic AND
61
	if length(Truths) == N -> Caller ! {dont_care, lists:min(Truths)};
62
	   true -> true
63
	end,
64
	receive
65
		{_, Truth} -> collect([Truth | Truths], N, Caller)
66
	end.