Provenance
pd2af.building.provenance
Where each output element comes from, and the metadata it inherits.
Provenance maps each output element to the input elements it derives from;
:func:make_provenance_from_context builds it from the slots the model pass
filled, and :func:carry_annotations_through_provenance reads it back to
re-key the input annotations and notes onto the output.
momapy stores annotations and notes not on model elements but in side-tables on
the ReaderResult (element_to_annotations / element_to_notes, each a
Mapping[model_element -> frozenset]). The transform builds new output
elements, so those input-keyed side-tables no longer address anything in the
output map. This module re-keys them onto the output elements through the
transform's provenance -- which maps each output element to the input elements
it derives from -- unioning the annotations/notes of every merged source onto
their shared output element.
Functions:
| Name | Description |
|---|---|
carry_annotations_through_provenance |
Re-key input annotation/note side-tables onto the output elements. |
make_provenance_from_context |
Build the output-element -> input-elements provenance mapping. |
record_provenance_for_subunit_trees |
Pair the subunits of an |
carry_annotations_through_provenance
carry_annotations_through_provenance(provenance: FrozenIdentityMultiDict, input_element_to_annotations: dict | None, input_element_to_notes: dict | None, input_map: Any = None, output_map: Any = None) -> tuple[dict, dict]
Re-key input annotation/note side-tables onto the output elements.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provenance
|
FrozenIdentityMultiDict
|
the transform's |
required |
input_element_to_annotations
|
dict | None
|
|
required |
input_element_to_notes
|
dict | None
|
|
required |
input_map
|
Any
|
the input map, whose own annotations/notes are keyed by the
map object itself (the map is not a provenance element); pass it
with |
None
|
output_map
|
Any
|
the output map -- the key the writer looks the map-level annotations up under. |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
An |
dict
|
plain dicts keyed by output model element with |
tuple[dict, dict]
|
ready to hand to the momapy writer. For every output element the |
tuple[dict, dict]
|
annotations/notes of all its provenance input sources are unioned, so a |
tuple[dict, dict]
|
merged activity gathers the metadata of every proteoform that collapsed |
tuple[dict, dict]
|
into it. |
Source code in src/pd2af/building/provenance.py
make_provenance_from_context
make_provenance_from_context(context: BuilderContext) -> FrozenIdentityMultiDict
Build the output-element -> input-elements provenance mapping.
Provenance answers "where did this output come from": it maps each output
AF element to the frozenset of input PD/CD elements it derives from. The
relation is many-to-one -- the merged modes content-dedup several input
proteoforms (or compartments) into one output -- so the origin direction is
the genuinely multi-valued one, keyed by output.
Walks the key_to_* dicts the model pass populates for every activity
and operator atom (the *_emissions lists only record the first element
per identity and would miss the many-to-one dedup pairings). Each activity
key carries the input element's clingo id in key.species and each
operator key in key.gate; both resolve back to the input model element
through context.clingo_id_to_model_element. Compartments are folded in
from context.compartment_emissions (already input/output element pairs).
The subunits of a complex are provenance keys too, paired by
:func:record_provenance_for_subunit_trees from the species pairs above so
that annotations and notes carried on a subunit reach the output subunit
that stands for it. Provenance keys are therefore the output species (or
activities), their subunits at any depth, the gates (or operators) and the
compartments.
Returns a :class:momapy.utils.FrozenIdentityMultiDict whose forward maps
each output element to the frozenset of input elements it derives from,
and whose .inverse (keyed by id(input_element)) recovers the output.
Source code in src/pd2af/building/provenance.py
record_provenance_for_subunit_trees
record_provenance_for_subunit_trees(output_species: Any, input_species: Any, input_model_element_to_canonical_model_element: dict, record_pair: Callable[[Any, Any], None]) -> None
Pair the subunits of an (output_species, input_species) pair.
Each pairing is recorded, recursing to arbitrary depth for nested complexes.
Subunits are never activity keys -- the ASP resolvesToTopLevel relation
resolves a subunit at any depth to its outermost complex -- so they reach
provenance only through this walk. Pairing cannot be positional (subunits is a
frozenset) nor by identity (the merged modes rebuild every subunit while
stripping, and the kept modes may keep a content-equal twin from another
complex). Each input subunit resolves to an output subunit through
input_model_element_to_canonical_model_element, the
id(input) -> canonical map the model pass records while stripping and
promoting, and falls back to content-equality (momapy model elements are
frozen dataclasses excluding id_ from __eq__/__hash__, so a dict
keyed by subunit is a content index). The canonical is accepted only when it
is a subunit of the paired output complex, keeping every recorded key a
genuine part of that complex.
A no-op for elements without subunits: SBGN-AF activities, logical operators, gates and compartments.