diff --git a/corneto/contrib/annnet.py b/corneto/contrib/annnet.py index 110950348..b6c6d0239 100644 --- a/corneto/contrib/annnet.py +++ b/corneto/contrib/annnet.py @@ -18,7 +18,7 @@ from annnet import AnnNet -_ANNNET_VERTEX_RESERVED = {"layer", "slice", "vertex_id"} +_ANNNET_NODE_RESERVED = {"layer", "slice", "node_id"} _ANNNET_EDGE_RESERVED = { "as_entity", "default_edge_directed", @@ -102,22 +102,22 @@ def to_annnet(graph: BaseGraph, *, copy_attributes: bool = True) -> "AnnNet": annnet = import_optional_module("annnet") result = annnet.AnnNet(directed=None) - vertex_ids = {} + node_ids = {} used_ids = set() for vertex in graph.V: - vertex_id = str(vertex) - if vertex_id in used_ids: - raise ValueError(f"Multiple CORNETO vertices map to AnnNet vertex {vertex_id!r}.") - used_ids.add(vertex_id) - vertex_ids[vertex] = vertex_id + node_id = str(vertex) + if node_id in used_ids: + raise ValueError(f"Multiple CORNETO vertices map to AnnNet node {node_id!r}.") + used_ids.add(node_id) + node_ids[vertex] = node_id attributes = {} if copy_attributes: attributes = _copy_supported_attributes( graph.get_attr_vertex(vertex), - _ANNNET_VERTEX_RESERVED, - "vertex", + _ANNNET_NODE_RESERVED, + "node", ) - result.add_vertices(vertex_id, **attributes) + result.add_nodes(node_id, **attributes) if copy_attributes: result.uns.update(deepcopy(dict(graph.get_graph_attributes()))) @@ -143,8 +143,8 @@ def to_annnet(graph: BaseGraph, *, copy_attributes: bool = True) -> "AnnNet": "edge", ) - annnet_source = [vertex_ids[v] for v in source] - annnet_target = [vertex_ids[v] for v in target] + annnet_source = [node_ids[v] for v in source] + annnet_target = [node_ids[v] for v in target] uniform_weight = _uniform_magnitude(source, target, edge_attributes) if not directed: @@ -174,8 +174,8 @@ def to_annnet(graph: BaseGraph, *, copy_attributes: bool = True) -> "AnnNet": source_arg = annnet_source[0] if len(annnet_source) == 1 else annnet_source target_arg = annnet_target[0] if len(annnet_target) == 1 else annnet_target else: - source_arg = {vertex_ids[v]: -_endpoint_magnitude(edge_attributes, Attr.SOURCE_ATTR, v) for v in source} - target_arg = {vertex_ids[v]: _endpoint_magnitude(edge_attributes, Attr.TARGET_ATTR, v) for v in target} + source_arg = {node_ids[v]: -_endpoint_magnitude(edge_attributes, Attr.SOURCE_ATTR, v) for v in source} + target_arg = {node_ids[v]: _endpoint_magnitude(edge_attributes, Attr.TARGET_ATTR, v) for v in target} result.add_edges( source_arg, @@ -219,18 +219,18 @@ def from_annnet(graph: "AnnNet", *, copy_attributes: bool = True) -> Graph: result = Graph() result.get_graph_attributes().update(graph_attributes) - vertices = list(graph.vertices()) - for vertex in vertices: + nodes = list(graph.nodes()) + for vertex in nodes: attributes = {} if copy_attributes: - attributes = dict(graph.attrs.get_vertex_attrs(vertex)) - attributes.pop("vertex_id", None) + attributes = dict(graph.attrs.get_node_attrs(vertex)) + attributes.pop("node_id", None) result.add_vertex(vertex, **deepcopy(attributes)) edge_ids = list(graph.edges()) directed_edge_ids = set(graph.get_edges_by_direction(True)) - matrix = graph.X() - row_by_vertex = {graph.get_vertex(i): i for i in range(graph.nv)} + matrix = graph.S + row_by_vertex = {graph.N[i]: i for i in range(graph.nv)} for edge_index, edge_id in enumerate(edge_ids): edge = graph.get_edge(edge_id) diff --git a/corneto/methods/signaling/annnet.py b/corneto/methods/signaling/annnet.py index 0f209a5ca..2eb7db91e 100644 --- a/corneto/methods/signaling/annnet.py +++ b/corneto/methods/signaling/annnet.py @@ -106,11 +106,11 @@ def add_cellnopt_conditions( {condition_aspect: list(condition_names)}, ) - known_vertices = set(graph.vertices()) - base_vertices = list(graph.vertices()) + known_nodes = set(graph.nodes()) + base_nodes = list(graph.nodes()) layers = {condition: (condition,) for condition in condition_names} for condition, layer in layers.items(): - graph.add_vertices(base_vertices, layer=layer) + graph.add_nodes(base_nodes, layer=layer) values_by_role = ( (inputs[condition], input_attr), (inhibitors[condition], inhibitor_attr), @@ -119,12 +119,12 @@ def add_cellnopt_conditions( for values, attribute in values_by_role: if not isinstance(values, Mapping): raise TypeError(f"Values for condition {condition!r} must be mappings keyed by protein.") - unknown = set(values) - known_vertices + unknown = set(values) - known_nodes if unknown: protein = sorted(unknown, key=str)[0] raise ValueError(f"Unknown protein {protein!r} in condition {condition!r}.") for protein, value in values.items(): - graph.layers.set_vertex_layer_attrs(str(protein), layer, **{attribute: value}) + graph.layers.set_node_attrs(str(protein), layer, **{attribute: value}) return layers @@ -201,9 +201,9 @@ def build_cellnopt_from_annnet( inputs[condition] = {} inhibitors[condition] = {} measurements[condition] = {} - for protein in graph.layers.layer_vertex_set(layer): + for protein in graph.layers.layer_node_set(layer): protein_id = str(protein[0]) if isinstance(protein, tuple) else str(protein) - attributes = graph.layers.get_vertex_layer_attrs(protein_id, layer) + attributes = graph.layers.node_attrs(protein_id, layer) if input_attr in attributes: inputs[condition][protein_id] = attributes[input_attr] if attributes.get(inhibitor_attr): @@ -292,17 +292,17 @@ def add_cellnopt_results( condition_errors = {} for condition_index, condition in enumerate(condition_names): layer = context.condition_layers[condition] - graph.add_vertices(vertices, layer=layer) + graph.add_nodes(vertices, layer=layer) endpoint_error = 0.0 for vertex_index, protein in enumerate(vertices): predicted = float(predictions[vertex_index, condition_index]) attributes = {prediction_attr: predicted} - existing = graph.layers.get_vertex_layer_attrs(protein, layer) + existing = graph.layers.node_attrs(protein, layer) if measurement_attr in existing: error = abs(predicted - float(existing[measurement_attr])) attributes[error_attr] = error endpoint_error += error - graph.layers.set_vertex_layer_attrs(protein, layer, **attributes) + graph.layers.set_node_attrs(protein, layer, **attributes) condition_edges = [] for reaction_index in selected_indices: @@ -344,7 +344,7 @@ def add_cellnopt_results( } if solution is not None and getattr(solution, "status", None) is not None: layer_attributes["solver_status"] = str(solution.status) - graph.layers.set_layer_attrs(layer, **layer_attributes) + graph.layers.set_attrs(layer, **layer_attributes) condition_errors[condition] = endpoint_error graph.history.snapshot("cellnopt_results_added") diff --git a/docs/guide/interoperability/annnet.md b/docs/guide/interoperability/annnet.md index 22211535d..3b1c7794f 100644 --- a/docs/guide/interoperability/annnet.md +++ b/docs/guide/interoperability/annnet.md @@ -34,7 +34,7 @@ restored = from_annnet(annotated) ``` Directed binary edges and hyperedges, parallel edges, endpoint coefficients, -and ordinary graph, vertex, and edge attributes are preserved. CORNETO edge +and ordinary graph, node, and edge attributes are preserved. CORNETO edge indices become AnnNet IDs such as `corneto_edge_0`. When converting in the other direction, the original AnnNet ID is stored as the CORNETO edge attribute `_annnet_edge_id`. @@ -46,8 +46,8 @@ hypergraphs normally used by CORNETO: - AnnNet layers, slice membership, edge-entities, and flexible direction policies are not reproduced in CORNETO. -- Vertex identifiers are converted to strings for AnnNet. A collision after - conversion raises an error. +- A CORNETO vertex identifier becomes an AnnNet node id, as a string. A + collision after conversion raises an error. - CORNETO edges with an empty source or target set are not supported. - An undirected hyperedge is converted as one member set. Its original CORNETO source/target partition cannot be recovered; converting it back uses diff --git a/docs/tutorials/annnet-signaling/annnet-cellnopt-dag.ipynb b/docs/tutorials/annnet-signaling/annnet-cellnopt-dag.ipynb index 5846ab81c..5f63de35c 100644 --- a/docs/tutorials/annnet-signaling/annnet-cellnopt-dag.ipynb +++ b/docs/tutorials/annnet-signaling/annnet-cellnopt-dag.ipynb @@ -133,10 +133,10 @@ "signaling = an.AnnNet(directed=True)\n", "signaling.history.enable(True)\n", "signaling.slices.add(\"prior\", role=\"prior_knowledge\")\n", - "signaling.add_vertices(sorted(display_name))\n", + "signaling.add_nodes(sorted(display_name))\n", "\n", "for protein, label in display_name.items():\n", - " signaling.attrs.set_vertex_attrs(protein, label=label, entity_type=\"protein\")\n", + " signaling.attrs.set_node_attrs(protein, label=label, entity_type=\"protein\")\n", "\n", "prior_edge_ids = []\n", "for index, (source, sign, target) in enumerate(pkn_edges):\n", @@ -495,7 +495,7 @@ " signaling,\n", " backend=\"graphviz\",\n", " layout=\"dot\",\n", - " vertex_label_key=\"label\",\n", + " node_label_key=\"label\",\n", " use_weight_style=False,\n", " graph_attr={\"rankdir\": \"LR\", \"size\": \"12,7\"},\n", " node_attr={\"shape\": \"ellipse\", \"style\": \"filled\", \"fillcolor\": \"#eef4fb\"},\n", @@ -599,12 +599,12 @@ }, "outputs": [], "source": [ - "def vertex_layer_table(network, layers, columns):\n", - " \"\"\"Return selected vertex-layer attributes as a pandas table.\"\"\"\n", + "def node_layer_table(network, layers, columns):\n", + " \"\"\"Return selected node-layer attributes as a pandas table.\"\"\"\n", " rows = {}\n", " for condition, layer in layers.items():\n", " rows[condition] = {\n", - " label: network.layers.get_vertex_layer_attrs(protein, layer).get(attribute, np.nan)\n", + " label: network.layers.node_attrs(protein, layer).get(attribute, np.nan)\n", " for label, (protein, attribute) in columns.items()\n", " }\n", " return pd.DataFrame.from_dict(rows, orient=\"index\").rename_axis(\"condition\")" @@ -818,7 +818,7 @@ " \"AKT observed\": (\"akt\", \"observed\"),\n", " \"HSP27 observed\": (\"hsp27\", \"observed\"),\n", "}\n", - "experiment = vertex_layer_table(signaling, condition_layers, experiment_columns).fillna(0)\n", + "experiment = node_layer_table(signaling, condition_layers, experiment_columns).fillna(0)\n", "experiment" ] }, @@ -1790,7 +1790,7 @@ } ], "source": [ - "akt_response = vertex_layer_table(\n", + "akt_response = node_layer_table(\n", " signaling,\n", " condition_layers,\n", " {\n", @@ -2000,7 +2000,7 @@ "an.io.write(signaling, analysis_path, overwrite=True)\n", "restored = an.io.read(analysis_path)\n", "\n", - "restored_akt = vertex_layer_table(\n", + "restored_akt = node_layer_table(\n", " restored,\n", " condition_layers,\n", " {\n", diff --git a/tests/contrib/test_annnet.py b/tests/contrib/test_annnet.py index de31e116f..322bd8524 100644 --- a/tests/contrib/test_annnet.py +++ b/tests/contrib/test_annnet.py @@ -20,13 +20,13 @@ def test_directed_hypergraph_roundtrip(): converted = to_annnet(graph) - assert converted.vertices() == ["A", "B", "C"] + assert converted.nodes() == ["A", "B", "C"] assert converted.get_edge("corneto_edge_0") == ( frozenset({"A", "B"}), frozenset({"C"}), ) assert converted.get_edges_by_direction(True) == ["corneto_edge_0"] - assert converted.attrs.get_vertex_attrs("A")["kind"] == "gene" + assert converted.attrs.get_node_attrs("A")["kind"] == "gene" assert converted.attrs.get_edge_attrs("corneto_edge_0")["relation"] == "reaction" assert converted.uns["name"] == "example" @@ -77,23 +77,23 @@ def test_undirected_hyperedge_is_canonicalized_to_member_set(): assert restored.get_attr_edge(0).get_attr(Attr.EDGE_TYPE) == EdgeType.UNDIRECTED.value -def test_non_string_vertex_ids_are_converted_to_strings(): +def test_non_string_node_ids_are_converted_to_strings(): """CORNETO vertex identifiers are stringified for AnnNet.""" graph = Graph() graph.add_edge(1, 2) converted = to_annnet(graph) - assert converted.vertices() == ["1", "2"] + assert converted.nodes() == ["1", "2"] -def test_string_conversion_rejects_vertex_id_collisions(): +def test_string_conversion_rejects_node_id_collisions(): """Stringification cannot silently merge distinct CORNETO vertices.""" graph = Graph() graph.add_vertex(1) graph.add_vertex("1") - with pytest.raises(ValueError, match="map to AnnNet vertex"): + with pytest.raises(ValueError, match="map to AnnNet node"): to_annnet(graph) diff --git a/tests/methods/signaling/test_cellnopt_annnet.py b/tests/methods/signaling/test_cellnopt_annnet.py index 0dd81f0b2..d3f246e57 100644 --- a/tests/methods/signaling/test_cellnopt_annnet.py +++ b/tests/methods/signaling/test_cellnopt_annnet.py @@ -39,10 +39,10 @@ def test_cellnopt_reads_conditions_and_adds_results_to_annnet(backend): assert solution.status == "optimal" assert layers == {"off": ("off",), "on": ("on",), "blocked": ("blocked",)} - assert graph.layers.get_vertex_layer_attrs("L", ("on",))["input"] == 1 - assert graph.layers.get_vertex_layer_attrs("A", ("blocked",))["inhibited"] == 1 - assert graph.layers.get_vertex_layer_attrs("Y", ("on",))["predicted"] == 1 - assert graph.layers.get_layer_attrs(("blocked",))["endpoint_absolute_error"] == 0 + assert graph.layers.node_attrs("L", ("on",))["input"] == 1 + assert graph.layers.node_attrs("A", ("blocked",))["inhibited"] == 1 + assert graph.layers.node_attrs("Y", ("on",))["predicted"] == 1 + assert graph.layers.attrs(("blocked",))["endpoint_absolute_error"] == 0 assert graph.slices.exists("cellnopt_selected") assert summary["selected_reactions"] == 2 assert summary["condition_errors"] == {"off": 0.0, "on": 0.0, "blocked": 0.0}