Skip to content
Browse files

Implemented support of not connected by variables patterns.

  • Loading branch information...
1 parent 6ddae13 commit be432d049368389d0fc0e4b72a8a2a9feadf909d @vjache committed
Showing with 94 additions and 33 deletions.
  1. +1 −1 TODO
  2. +2 −2 rebar.config
  3. +49 −20 src/elips.erl
  4. +39 −7 src/elips_engine.erl
  5. 0 start-shell.sh
  6. +1 −1 test-pt.sh
  7. +2 −2 test/victim.erl
View
2 TODO
@@ -23,7 +23,7 @@
5. Give access to alpha memory form a call back module
6*. Back tracking & goal satisfaction
-Known Bugs
+Known Bugs [fixed]
1. LHS patterns not connected by variables i.e. having more that one
connected components by vars are incorrectly handled.
View
4 rebar.config
@@ -1,6 +1,6 @@
-{erl_opts, [warnings_as_errors, debug_info]}.
+{erl_opts, [debug_info]}.
{xref_checks, [undefined_function_calls]}.
{dialyzer_opts, [{warnings, [unmatched_returns]}]}.
-
+{eunit_opts, [verbose, {report,{eunit_surefire,[{dir,"."}]}}]}.
{cover_enabled, true}.
{clean_files, [".eunit", "ebin/*.beam"]}.
View
69 src/elips.erl
@@ -247,9 +247,20 @@ handle_({Module, Function, Args} = MFA, State) ->
handle_data(EState0, _Module, _WMEts, []) ->
EState0;
handle_data(EState0, Module, WMEts, WMOList) ->
+ ModifyEntry=
+ fun(Op, Entry) ->
+ EntryExists=([[]]==ets:match(WMEts, Entry)),
+ case {Op,EntryExists} of
+ {assert, false} -> ets:insert(WMEts, Entry);
+ {retire, true} -> ets:delete_object(WMEts, Entry);
+ _ -> false
+ end
+ end,
% Create enivronment function for engine logic
Env=fun(get_bnode, [BNodeId])->
Module:beta_node(BNodeId); % Generated by parse transform
+ (get_pnode, [PNodeId])->
+ Module:p_node(PNodeId); % Generated by parse transform
(get_anodes, []) ->
Module:alpha_nodes(); % Generated by parse transform
(fetch_left_index, [BNodeId, {}]) ->
@@ -258,30 +269,37 @@ handle_data(EState0, Module, WMEts, WMOList) ->
true -> [ [ ] ];
false -> [ ]
end;
+ (fetch_pnode_tokens, [PNodeId, BNodeId]) ->
+ try ets:lookup_element(WMEts, {p,PNodeId, BNodeId}, 2) catch _:badarg -> [] end;
(fetch_left_index, [BNodeId, Key]) ->
try ets:lookup_element(WMEts, {li,BNodeId,Key}, 2) catch _:badarg -> [] end;
(fetch_right_index, [BNodeId, Key]) ->
try ets:lookup_element(WMEts, {ri,BNodeId,Key}, 2) catch _:badarg -> [] end;
+ (modify_pnode_tokens, [PNodeId, FromBNodeId, Op, Token]) ->
+ Entry={ {p,PNodeId,FromBNodeId}, Token },
+ ModifyEntry(Op, Entry);
(modify_left_index, [BNodeId, Key, assert, Token]) ->
Entry={ {li,BNodeId,Key}, Token},
ets:insert(WMEts, Entry),ok;
(modify_left_index, [BNodeId, Key, retire, Token]) ->
Entry={ {li,BNodeId,Key}, Token},
ets:delete_object(WMEts, Entry),ok;
- (modify_right_index, [BNodeId, Key, assert, WME]) ->
- Entry={ {ri,BNodeId,Key} , WME},
- case ets:match(WMEts, Entry) of
- [ [] ] -> false;
- [] -> true=ets:insert(WMEts, Entry)
- end;
- (modify_right_index, [BNodeId, Key, retire, WME]) ->
+ (modify_right_index, [BNodeId, Key, Op, WME]) ->
Entry={ {ri,BNodeId,Key} , WME},
- case ets:match(WMEts, Entry) of
- [ [] ] -> true=ets:delete_object(WMEts, Entry);
- [] -> false
- end;
- (activate_pnode, [BNodeId, Op, _PNode, Token]) ->
- {token, BNodeId, Op, Token}
+ ModifyEntry(Op, Entry);
+ (activate_pnode, [_BNodeId, _Op, _PNode, {cart, _TokenFormat, _LLT}=Cart]) ->
+ Cart;
+ (activate_pnode, [_BNodeId, _Op, _PNode, Token]) ->
+ {token, Token}
+ end,
+ FoldToken=
+ fun(Token,WMO, {EStateAcc, WMOAcc})->
+ % Pass activated token to behavior handle_pattern
+ case Module:handle_pattern(Token, WMO, EStateAcc) of
+ noop -> {EStateAcc, WMOAcc};
+ {ok, EState1} -> {EState1, WMOAcc};
+ {ok, EState1, WMOData} -> {EState1, [WMOData, WMOAcc] }
+ end
end,
{EStateZ, WMOListZ}=
lists:foldl( % Fold each Working Memory Operation in WMOList
@@ -292,15 +310,26 @@ handle_data(EState0, Module, WMEts, WMOList) ->
{EStateAcc0, WMOAcc0};
ATokens -> % There are tokens activated
lists:foldl( % Fold each activated token into elips state
- fun({token, _BNodeId, _Op, Token}, {EStateAcc, WMOAcc}) ->
- % Pass activated token to behavior handle_pattern
- case Module:handle_pattern(Token, WMO, EStateAcc) of
- noop -> {EStateAcc, WMOAcc};
- {ok, EState1} -> {EState1, WMOAcc};
- {ok, EState1, WMOData} -> {EState1, [WMOData, WMOAcc] }
- end
+ fun({token, Token}, Acc) ->
+ FoldToken(Token, WMO, Acc);
+ ({cart, TokenFormat, LLT}, Acc) ->
+ foldl_cart(
+ fun(LT,Acc1)->
+ Token=TokenFormat(LT),
+ FoldToken(Token, WMO, Acc1)
+ end,Acc,LLT)
end, {EStateAcc0, WMOAcc0}, ATokens)
end
end, {EState0, []}, WMOList),
handle_data(EStateZ, Module, WMEts, lists:flatten(WMOListZ) ).
+foldl_cart(F,Acc0,LL)->
+ foldl_cart(F,Acc0,LL,[]).
+foldl_cart(F,Acc0,[],Token) ->
+ F(lists:reverse(Token),Acc0);
+foldl_cart(F,Acc0,[L|T],Token) ->
+ lists:foldl(
+ fun(E,Acc)->
+ foldl_cart(F,Acc,T, [E|Token])
+ end,Acc0,L).
+
View
46 src/elips_engine.erl
@@ -71,7 +71,7 @@ join_left_bnode(#bnode{id=Id,left_key_fun=LeftKeyFun}=BNode, _Op, Token, Env) ->
new_token(WME, Token) ->
Token ++ [WME].
-downstream_tokens(#bnode{id=Id,bnode_ids=BNodeIds,pnodes=PNodes}=BNode, _Op, Tokens, Env) ->
+downstream_tokens(#bnode{id=Id,bnode_ids=BNodeIds,pnodes=PNodeIds}=BNode, _Op, Tokens, Env) ->
% Filter tokens with b-node match critera (e.g. check additional guards before output)
MatchedTokens=[ T || T <- Tokens, match_token(BNode, T)],
% Each matched token pass to the next b-nodes (i.e. downstreaming)
@@ -81,14 +81,37 @@ downstream_tokens(#bnode{id=Id,bnode_ids=BNodeIds,pnodes=PNodes}=BNode, _Op, Tok
join_left_bnode(NextBNode, _Op, Token, Env)
end || Token <- MatchedTokens, BNodeId <- BNodeIds],
% Each matched token pass to output nodes (p-nodes) if any
- ActResult=
- if PNodes ->
- [activate_pnode(Id, _Op, true, Token, Env) || Token <- MatchedTokens];
- true ->
- []
- end,
+ ActResult=[push_token_to_pnode(Id, _Op, PNodeId, Token, Env) || Token <- MatchedTokens, PNodeId <- PNodeIds],
[ActResult, ActResults].
+push_token_to_pnode(FromBNodeId, WMO, PNodeId, Token, Env) ->
+ PNode=#pnode{bnode_ids=BNodeIds,token_format=TokenFormat}=get_pnode(PNodeId,Env),
+ case BNodeIds of
+ [FromBNodeId] -> % Simple case
+ activate_pnode(FromBNodeId, WMO, PNode, TokenFormat([Token]), Env);
+ [_,_|_] -> % Cartesian product case
+ % 1. Add pnode tokens for bnode data received from
+ IsModified=modify_pnode_tokens(PNodeId, FromBNodeId, WMO, Token, Env), % TODO: It seems we don't
+ % need to analyze whether
+ % the data were modified,
+ % because of this is already
+ % done at alpha layer.
+ case IsModified of
+ % 2a. In case modification occured read all components for product
+ true ->
+ % TODO: Optimize. If some fetch results with [] then stop & return []
+ LLT=[if BNodeId==FromBNodeId -> [Token];
+ true -> fetch_pnode_tokens(PNodeId, BNodeId, Env)
+ end || BNodeId <- BNodeIds ],
+ case lists:any(fun(L)-> L==[] end, LLT) of
+ true -> [];
+ false -> activate_pnode(FromBNodeId, WMO, PNode, {cart, TokenFormat, LLT}, Env)
+ end;
+ % 2b. Token have no effect
+ false -> []
+ end
+ end.
+
match_anodes(WME, Env) ->
[ ANode || ANode <- get_anodes(Env), match_anode(ANode, WME)].
@@ -113,18 +136,27 @@ get_bnode(BNodeId,Env) ->
get_anodes(Env) ->
Env(get_anodes,[]).
+get_pnode(PNodeId,Env) ->
+ Env(get_pnode,[PNodeId]).
+
fetch_left_index(BNodeId, Key, Env) ->
Env(fetch_left_index, [BNodeId, Key]).
fetch_right_index(BNodeId, Key, Env) ->
Env(fetch_right_index, [BNodeId, Key]).
+fetch_pnode_tokens(PNodeId, BNodeId, Env) ->
+ Env(fetch_pnode_tokens, [PNodeId, BNodeId]).
+
modify_left_index(BNodeId, Key, Op, Token, Env) ->
ok=Env(modify_left_index, [BNodeId, Key, Op, Token]).
modify_right_index(BNodeId, Key, {Op, WME}, Env) ->
Env(modify_right_index, [BNodeId, Key, Op, WME]).
+modify_pnode_tokens(PNodeId, FromBNodeId, Op, Token, Env) ->
+ Env(modify_pnode_tokens, [PNodeId, FromBNodeId, Op, Token]).
+
activate_pnode(Id, _Op, PNode, Token, Env) ->
Env(activate_pnode, [Id, _Op, PNode, Token]).
View
0 start-shell.sh 100644 → 100755
File mode changed.
View
2 test-pt.sh 100644 → 100755
@@ -2,4 +2,4 @@
export ERL_LIBS=..\
-erlc -I include/ test/victim_0.erl
+erlc -I include/ test/victim.erl
View
4 test/victim.erl
@@ -74,8 +74,8 @@ init(ReplyPid) ->
-spec handle_pattern(Token :: [term()], WMO :: elips:wmo(term()), State :: term() ) -> elips:ok_reply() | noop.
handle_pattern(
[{_A,has,_B},
- {_C,is_a,dog},
- {_B,has,_C}]=P,
+ {_B,has,_C},
+ {_C,is_a,dog}]=P,
#assert{}, #state{reply_to=ReplyPid}=_State) ->
ReplyPid ! P,
noop;

0 comments on commit be432d0

Please sign in to comment.
Something went wrong with that request. Please try again.