Two agents each hold three datasets and each has a policy. Agent 1 wants three datasets from agent 2. A negotiation succeeds only when the asking side lacks the data, the other side has it, and both policies allow the exchange. Of three requests, exactly one survives.
Run it in the playground · Source
Data sharing has two gatekeepers. The requester’s own policy decides what it may ask for, and the provider’s policy decides what it may hand over. A request that one side would refuse is not worth sending, so the reasoner checks both sides before anyone acts.
hasData(agent1, [data1, data2, data3]).
hasData(agent2, [data4, data5, data6]).
want_negotiate(agent1, [agent2, data4]).
want_negotiate(agent1, [agent2, data5]).
want_negotiate(agent1, [agent2, data7]).
policy(agent1, [request, Data]) :-
member(Data, [data4, data6]).
policy(agent2, [accept, Data]) :-
(Data \= data5).
Agent 1 may request only data4 and data6. Agent 2 will share anything
except data5. Nobody holds data7.
request_data(Agenta, Agentb, Data) :-
hasData(Agenta, Datalista),
hasData(Agentb, Datalistb),
member(Data, Datalistb),
\+ member(Data, Datalista),
policy(Agenta, [request, Data]).
negotiate(Agenta, [Agentb, Data]) :-
want_negotiate(Agenta, [Agentb, Data]),
request_data(Agenta, Agentb, Data),
accept_request(Agentb, Agenta, Data).
A request is possible when the provider has the data, the requester does not, and the requester’s policy allows asking. A negotiation needs the wish, the request, and the provider’s acceptance.
eyeprolog examples/data-negotiation.pl
negotiate(agent1, [agent2, data4]).
data4 goes through. data5 fails twice: agent 1 may not ask for it, and
agent 2 would refuse it anyway. data7 fails because agent 2 does not have it.
step(request_data(agent1, agent2, data4),
rule(8),
['Agenta' = agent1,
'Agentb' = agent2,
'Data' = data4,
'Datalista' = [data1, data2, data3],
'Datalistb' = [data4, data5, data6]],
[hasData(agent1, [data1, data2, data3]),
hasData(agent2, [data4, data5, data6]),
member(data4, [data4, data5, data6]),
\+ member(data4, [data1, data2, data3]),
policy(agent1, [request, data4])]).
The request is justified by both data inventories, by data4 being in agent
2’s list and not in agent 1’s, and by agent 1’s request policy. Every premise
the decision rests on is named.
condition('C1', resolution, ok, 8).
condition('C5', re_decision, ok, 4).
condition('C6', boundary_consistency, ok, 0).
steps(12).
trusted(0).
verdict(checked).
Eight steps are replayed and four recomputed: three member/2 calls and one
negation, “agent 1 does not already have data4”, written
\+ member(data4, [data1, data2, data3]). A failed search cannot be replayed
as a derivation, but this one is about a list written out in the step, so the
checker decides it again itself. Nothing is left as an assumption.
want_negotiate(agent1, [agent2, data6]). A second negotiation
succeeds, because both policies allow data6.data4. What is left?data1.Learn more in The Art of EyeProlog, Chapter 7 (failure and negation) and Chapter 25 (an auditable decision service).