Relations and Concepts

using AlgebraicAgents

This example demonstrates how to define and manipulate relations between agents and concepts in the AlgebraicAgents framework, and how to visualize these relations. We also demonstrate the concept of wires. Consider wires.jl for a more comprehensive example.

Define a simple hierarchy

Instantiate two agents

client = FreeAgent("client")
server = FreeAgent("server")
agent server with uuid 899416e2 of type FreeAgent 

Create a system (the “universe” in which they interact)

system = ⊕(client, server, name="System")
agent System with uuid 1726a7f8 of type FreeAgent 
   inner agents: 
    agent client with uuid 1e7a81be of type FreeAgent 
    agent server with uuid 899416e2 of type FreeAgent 

Communication wires

Client sends a request to Server

add_wire!(system;
    from = client,
    to = server,
    from_var_name = "request_payload",
    to_var_name = "incoming_request"
)
1-element Vector{NamedTuple{(:from, :from_var_name, :to, :to_var_name), <:Tuple{AbstractAlgebraicAgent, Any, AbstractAlgebraicAgent, Any}}}:
 (from = FreeAgent{name=client, uuid=1e7a81be, parent=FreeAgent{name=System, uuid=1726a7f8, parent=nothing}}, from_var_name = "request_payload", to = FreeAgent{name=server, uuid=899416e2, parent=FreeAgent{name=System, uuid=1726a7f8, parent=nothing}}, to_var_name = "incoming_request")

Server sends a response back to Client

add_wire!(system;
    from = server,
    to = client,
    from_var_name = "response_payload",
    to_var_name = "incoming_response"
)
2-element Vector{NamedTuple{(:from, :from_var_name, :to, :to_var_name), <:Tuple{AbstractAlgebraicAgent, Any, AbstractAlgebraicAgent, Any}}}:
 (from = FreeAgent{name=client, uuid=1e7a81be, parent=FreeAgent{name=System, uuid=1726a7f8, parent=nothing}}, from_var_name = "request_payload", to = FreeAgent{name=server, uuid=899416e2, parent=FreeAgent{name=System, uuid=1726a7f8, parent=nothing}}, to_var_name = "incoming_request")
 (from = FreeAgent{name=server, uuid=899416e2, parent=FreeAgent{name=System, uuid=1726a7f8, parent=nothing}}, from_var_name = "response_payload", to = FreeAgent{name=client, uuid=1e7a81be, parent=FreeAgent{name=System, uuid=1726a7f8, parent=nothing}}, to_var_name = "incoming_response")

Define generic Concepts

c_data = Concept("Data", Dict(:format => "binary")) # abstract container
c_request = Concept("Request", Dict(:purpose => "query")) # a kind of Data
c_response = Concept("Response", Dict(:purpose => "reply")) # a kind of Data
concept Response with uuid 14d67ed6 of type Concept

Bind all Concepts into our system

add_concept!.(Ref(system), [c_data, c_request, c_response])
3-element Vector{Vector{AbstractConcept}}:
 [Concept{name=Data, uuid=f2dd0e08, related_entities=}, Concept{name=Request, uuid=b41261b3, related_entities=}, Concept{name=Response, uuid=14d67ed6, related_entities=}]
 [Concept{name=Data, uuid=f2dd0e08, related_entities=}, Concept{name=Request, uuid=b41261b3, related_entities=}, Concept{name=Response, uuid=14d67ed6, related_entities=}]
 [Concept{name=Data, uuid=f2dd0e08, related_entities=}, Concept{name=Request, uuid=b41261b3, related_entities=}, Concept{name=Response, uuid=14d67ed6, related_entities=}]

Concept hierarchy

Request ⊂ Data

add_relation!(c_request, c_data, :is_a)
relation Request [concept] is_a Data [concept]

Response ⊂ Data

add_relation!(c_response, c_data, :is_a)
relation Response [concept] is_a Data [concept]

Set up Agent–Concept relations

Client produces requests and consumes responses

add_relation!(client, c_request,  :produces)
add_relation!(client, c_response, :consumes)
relation client [agent] consumes Response [concept]

Server consumes requests and produces responses

add_relation!(server, c_request,  :consumes)
add_relation!(server, c_response, :produces)
relation server [agent] produces Response [concept]

Print out the concepts.

for r in server.opera.concepts
    println(r)
end
Concept{name=Data, uuid=f2dd0e08, related_entities=Request, Response}
Concept{name=Request, uuid=b41261b3, related_entities=Data, client, server}
Concept{name=Response, uuid=14d67ed6, related_entities=Data, client, server}

Print out the the relations.

for r in server.opera.relations
    println(r)
end
AlgebraicAgents.ConceptRelation{from=Request, relation=is_a, to=Data}
AlgebraicAgents.ConceptRelation{from=Response, relation=is_a, to=Data}
AlgebraicAgents.ConceptRelation{from=client, relation=produces, to=Request}
AlgebraicAgents.ConceptRelation{from=client, relation=consumes, to=Response}
AlgebraicAgents.ConceptRelation{from=server, relation=consumes, to=Request}
AlgebraicAgents.ConceptRelation{from=server, relation=produces, to=Response}

Query related concepts/agents

println("Entities related to Data:")
for r in get_relations(c_data)
    println(r)
end

println("Entites that Client produces:")
for r in get_relations(client, :produces)
    println(r)
end

isrelated(client, c_request, :produces) == true
true

Visualize the wires and relations

Visualize the wiring diagram of the system (you can run run_graphviz on the resulting DOT string, see that function's documentation for more details)

wiring_diagram(system)
"digraph \"algagents\" {\n    compound=true;\n    node[color=Teal, fontsize=7.0, width=0.5, height=0.5, shape=circle];\n    1 [label=\"client\"]\n2 [label=\"server\"]\n3 [label=\"System\"]\n    \n3 -> 1 [len=1, penwidth=0.5, arrowsize=0.4, arrowtype=normal, style=dashed, fontsize=5.0, c" ⋯ 71 bytes ⋯ ", style=dashed, fontsize=5.0, color=grey]\n1 -> 2 [len=1, headlabel=request_payload, taillabel=incoming_request, arrowsize=0.3, arrow=normal, fontsize=7.0]\n2 -> 1 [len=1, headlabel=response_payload, taillabel=incoming_response, arrowsize=0.3, arrow=normal, fontsize=7.0]\n}"

Visualize the concept graph of the system

concept_graph(get_relation_closure(server))
"digraph \"algagents_relations\" {\n    rankdir=LR;\n    node [fontsize=10];\n  \"14d67ed6\" [label=\"Response\", shape=circle, style=filled, fontsize=7.0, width=0.5, height=0.5, fillcolor=lightblue, color=\"transparent\"];\n  \"f2dd0e08\" [label=\"Data\", shape=circle, style=filled, fon" ⋯ 656 bytes ⋯ "4];\n  \"1e7a81be\" -> \"14d67ed6\" [label=\"consumes\", fontsize=5, penwidth=0.5, arrowsize=0.4];\n  \"899416e2\" -> \"b41261b3\" [label=\"consumes\", fontsize=5, penwidth=0.5, arrowsize=0.4];\n  \"899416e2\" -> \"14d67ed6\" [label=\"produces\", fontsize=5, penwidth=0.5, arrowsize=0.4];\n}\n"

Manipulate relations and concepts

Remove the concept-to-concept relation

remove_relation!(c_data, c_request, :is_a)
6-element Vector{AlgebraicAgents.ConceptRelation}:
 relation Request [concept] is_a Data [concept]
 relation Response [concept] is_a Data [concept]
 relation client [agent] produces Request [concept]
 relation client [agent] consumes Response [concept]
 relation server [agent] consumes Request [concept]
 relation server [agent] produces Response [concept]

Remove the Fruit concept entirely

remove_concept!(server, c_request)
concept Request with uuid b41261b3 of type Concept