SHOW:
|
|
- or go back to the newest paste.
| 1 | %% Backward chaining | |
| 2 | ||
| 3 | -module(backward). | |
| 4 | -export([start/0,mainLoop/0,solveGoal/2,solveRule/2,collect/3]). | |
| 5 | ||
| 6 | start() -> | |
| 7 | %% Initialize KB | |
| 8 | ets:new(rules, [bag, named_table]), | |
| 9 | ets:insert(rules, {g,[d,e,f,h,i,j],1.0}),
| |
| 10 | ets:insert(rules, {g,[a,b,c],1.1}),
| |
| 11 | ets:insert(rules, {a,[],0.1}),
| |
| 12 | ets:insert(rules, {b,[],0.2}),
| |
| 13 | ets:insert(rules, {c,[],0.3}),
| |
| 14 | ets:insert(rules, {d,[],0.4}),
| |
| 15 | ets:insert(rules, {e,[],0.5}),
| |
| 16 | ets:insert(rules, {f,[],0.6}),
| |
| 17 | ets:insert(rules, {h,[],0.7}),
| |
| 18 | ets:insert(rules, {i,[],0.8}),
| |
| 19 | ets:insert(rules, {j,[],0.9}),
| |
| 20 | mainLoop(). | |
| 21 | ||
| 22 | mainLoop() -> | |
| 23 | Query = io:read("Enter query: "),
| |
| 24 | - | solveGoal(element(2, Query), self()), |
| 24 | + | if |
| 25 | Query == {ok, x} -> exit(normal);
| |
| 26 | - | {_, Truth} -> io:format("Answer is: ~w~n", [Truth])
|
| 26 | + | true -> ok |
| 27 | end, | |
| 28 | Daddy = spawn(backward, solveGoal, [element(2, Query), self()]), | |
| 29 | receive | |
| 30 | {_, Truth} -> io:format("Answer is: ~w~n", [Truth]),
| |
| 31 | exit(Daddy, ok) | |
| 32 | end, | |
| 33 | mainLoop(). | |
| 34 | ||
| 35 | solveGoal(Goal, Caller) -> | |
| 36 | %% Fetch rules... | |
| 37 | ApplicableRules = ets:match(rules,{Goal, '$1', '$2'}),
| |
| 38 | lists:foreach( | |
| 39 | - | true -> spawn(backward, solveRule, [RuleBody, self()]) |
| 39 | + | |
| 40 | if | |
| 41 | %% If RHS is null | |
| 42 | RuleBody == [] -> Caller ! {Goal, Truth};
| |
| 43 | %% If RHS contains subgoals | |
| 44 | true -> spawn_link(backward, solveRule, [RuleBody, self()]) | |
| 45 | - | {_, Truth} -> Caller ! {Goal, Truth}
|
| 45 | + | |
| 46 | ApplicableRules), | |
| 47 | receive | |
| 48 | %% Each message is of the form {goal,truth}
| |
| 49 | %% Just accept the 1st answer | |
| 50 | - | Collector = spawn(backward, collect, [[], N, Caller]), |
| 50 | + | {_, Truth} -> Caller ! {Goal, Truth}
|
| 51 | end. | |
| 52 | ||
| 53 | solveRule(RuleTail, Caller) -> | |
| 54 | - | fun(Subgoal) -> spawn(backward, solveGoal, [Subgoal, Collector]) end, |
| 54 | + | |
| 55 | Collector = spawn_link(backward, collect, [[], N, Caller]), | |
| 56 | %% For each subgoal in Rule | |
| 57 | %% Spawn a process to solve each subgoal | |
| 58 | lists:foreach( | |
| 59 | fun(Subgoal) -> spawn_link(backward, solveGoal, [Subgoal, Collector]) end, | |
| 60 | RuleTail). | |
| 61 | - | if length(Truths) == N -> Caller ! {dont_care, lists:min(Truths)};
|
| 61 | + | |
| 62 | %% Accumulate results | |
| 63 | collect(Truths, N, Caller) -> | |
| 64 | %% If we have N messages send back the answer | |
| 65 | %% Answer = min of truth values, equivalent to fuzzy-logic AND | |
| 66 | if length(Truths) == N -> Caller ! {dont_care, lists:sum(Truths)};
| |
| 67 | true -> true | |
| 68 | end, | |
| 69 | receive | |
| 70 | {_, Truth} -> collect([Truth | Truths], N, Caller)
| |
| 71 | end. |