graflo.architecture.evolution.inverse_edges¶
Realize declared inverses as explicit logical edges (add_inverse_edges).
Three layers are touched, and each follows from the edges the op creates:
- schema: for every directed edge
(S, T, r)withrmapped toinv, the edge(T, S, inv)is added unless it already exists. An inverse edge that the user already declared explicitly is left alone, including its ingestion. - profile: the new edge gets a copy of the forward edge's physical spec, minus its physical name (two logical types must not share one storage type).
- ingestion: the edge steps that write a forward relation whose inverse edge
was created get
emit_inverse, so the same rows write both. Nothing is generated: the mirror is taken at assembly, after the relation is resolved, so it does not matter how a step names its relation. A resource that already writes the inverse with a step of its own is left alone, and the resource's edge selectors (infer_edge_only/infer_edge_except/extra_weights) gain the mirrored triple.
Attributes¶
EdgeTriple = tuple[str, str, str]
module-attribute
¶
Classes¶
Functions:¶
declared_relation_map(edge_config, relations)
¶
{relation: declared inverse} for the relations an op realizes.
None selects every paired relation, both sides of each pair. Symmetric
relations are never selected: their realization is directed: false.
Raises:
| Type | Description |
|---|---|
ValueError
|
when no pair is declared, or a named relation has no pair. |
Source code in graflo/architecture/evolution/inverse_edges.py
mirror_resource_selectors(payload, relation_map, created)
¶
payload with its edge selectors extended to the created inverse edges.
infer_edge_only / infer_edge_except and extra_weights name edges
by triple, outside the pipeline. A selector that covers a forward edge is
given a twin covering its mirror, so the inverse is included in, excluded
from, or weighted by whatever the forward edge is.
Source code in graflo/architecture/evolution/inverse_edges.py
plan_inverse_edges(schema, relations)
¶
The relation map and the inverse edges add_inverse_edges would create.
Shared by the op and its inverse, so undoing removes exactly what applying added. Relations whose inverse is native are refused when named and skipped when the whole table is realized: they already have their inverse.
Raises:
| Type | Description |
|---|---|
ValueError
|
for an undeclared relation, or a named natively realized one. |
Source code in graflo/architecture/evolution/inverse_edges.py
plan_inverse_emission(manifest, relation_map, created)
¶
The edge steps that should mirror into the inverse edges in created.
Pure: reads the manifest, returns {resource: [step ref, ...]}. A step is
selected when what it writes has its inverse edge among created -- one
edge for a step with fixed endpoints and relation, any of them for a step
whose relation or endpoints come from the data. Steps already flagged, and
resources that write the inverse with a step of their own, are left out.
Source code in graflo/architecture/evolution/inverse_edges.py
schema_edges_with_inverses(edges, relation_map)
¶
edges plus (T, S, inv) for each directed (S, T, r) with r -> inv.
The inverse keeps the forward edge's payload (properties, identities, type)
but not its semantics or description: those describe the forward
reading, and grounding employs to the IRI of employed_by is wrong.
Undirected edges are not inverted; callers refuse them before getting here.