CRN#

Chemical reaction network construction, structure handling, querying, symmetry, Petri-net analysis, and visualization utilities.

Construct#

class synkit.CRN.Construct.abstract.AbstractReactionExtractor[source]#

Bases: object

Build abstract symbolic reaction networks from reaction SMILES lists or SynKit-style module/pathway JSON blocks.

This class supports configurable field names when extracting reactions from JSON-like input records.

Example#

extractor = KEGGExtractor()
data = extractor.build_module_json(
    "M00001",
    with_compounds=True,
    with_atom_maps=False,
)

abstractor = AbstractReactionExtractor()
network = abstractor.build(
    data=data,
    deduplicate=True,
    order="appearance",
)
build(reactions: Sequence[str] | None = None, *, data: Mapping[str, Any] | None = None, drop_missing_smiles_reactions: bool = True, deduplicate: bool = False, templates: Mapping[str, str] | None = None, order: str = 'appearance', reactant_join: str = '+', product_join: str = '+', prefix_module_in_reaction_id: bool = True, reaction_id_keys: Sequence[str] | None = None, reaction_smiles_keys: Sequence[str] | None = None, template_keys: Sequence[str] | None = None, save_as: str | Path | None = None) AbstractReactionNetwork[source]#

Convert full reaction SMILES into an abstract symbolic reaction network.

You may provide either a direct list of reaction SMILES or a module/pathway JSON block.

If data is provided, field names for reaction identifiers, reaction SMILES strings, and templates may be customized.

Parameters:
  • reactions (Optional[Sequence[str]]) – Direct reaction SMILES list.

  • data (Optional[Mapping[str, Any]]) – Module-like or pathway-like reaction JSON block.

  • drop_missing_smiles_reactions (bool) – Whether to skip records missing reaction SMILES.

  • deduplicate (bool) – Whether to remove identity and duplicate abstract reactions.

  • templates (Optional[Mapping[str, str]]) – Optional external mapping from reaction identifiers to templates.

  • order (str) – Molecule ordering strategy, one of "appearance" or "sorted".

  • reactant_join (str) – Join token for abstract reactants.

  • product_join (str) – Join token for abstract products.

  • prefix_module_in_reaction_id (bool) – Whether to prefix pathway reaction IDs with module IDs.

  • reaction_id_keys (Optional[Sequence[str]]) – Candidate keys used to find reaction identifiers in each reaction record.

  • reaction_smiles_keys (Optional[Sequence[str]]) – Candidate keys used to find reaction SMILES strings in each reaction record.

  • template_keys (Optional[Sequence[str]]) – Candidate keys used to find rule or template strings in each reaction record.

  • save_as (Optional[PathLike]) – Optional JSON output path.

Returns:

Abstract symbolic reaction network.

Return type:

AbstractReactionNetwork

Example#

extractor = KEGGExtractor()
data = extractor.build_module_json(
    "M00001",
    with_compounds=True,
    with_atom_maps=False,
)

abstractor = AbstractReactionExtractor()
network = abstractor.build(
    data=data,
    deduplicate=True,
    order="appearance",
    reaction_id_keys=["id", "kegg_id", "rid"],
    reaction_smiles_keys=["smiles", "reaction", "rxn_smiles"],
    template_keys=["rule", "template", "smirks"],
    save_as="M00001_abstract.json",
)
build_molecule_pool(parsed_reactions: Sequence[Tuple[List[str], List[str]]], *, order: str = 'appearance') List[str][source]#

Build the unique molecule pool from parsed reactions.

Parameters:
  • parsed_reactions (Sequence[Tuple[List[str], List[str]]]) – Parsed reaction sides as (reactants, products) tuples.

  • order (str) – Molecule ordering mode. Supported values are "appearance" and "sorted".

Returns:

Ordered unique molecule pool.

Return type:

List[str]

Raises:

ValueError – If order is not supported.

Example#

molecule_pool = abstractor.build_molecule_pool(
    parsed_reactions,
    order="appearance",
)
extract_reactions_and_templates(reactions: Sequence[str] | None = None, *, data: Mapping[str, Any] | None = None, templates: Mapping[str, str] | None = None, drop_missing_smiles_reactions: bool = True, prefix_module_in_reaction_id: bool = True, reaction_id_keys: Sequence[str] | None = None, reaction_smiles_keys: Sequence[str] | None = None, template_keys: Sequence[str] | None = None) Tuple[List[str], Dict[str, str]][source]#

Extract reaction SMILES and rule-template mappings from raw inputs.

Either a direct list of reaction SMILES or a JSON data block may be provided. If both are given, the explicit reactions list takes precedence for reaction extraction, while templates is still merged.

When data is used, the user may customize which keys are searched for reaction identifiers, reaction SMILES strings, and templates.

Parameters:
  • reactions (Optional[Sequence[str]]) – Direct reaction SMILES list.

  • data (Optional[Mapping[str, Any]]) – Module-like or pathway-like JSON block.

  • templates (Optional[Mapping[str, str]]) – Optional external mapping from reaction identifiers to templates.

  • drop_missing_smiles_reactions (bool) – Whether to skip records that do not contain a reaction SMILES string.

  • prefix_module_in_reaction_id (bool) – Whether to prefix reaction identifiers with module IDs in pathway-style inputs.

  • reaction_id_keys (Optional[Sequence[str]]) – Candidate keys used to find reaction identifiers in each reaction record. The keys are tried in order.

  • reaction_smiles_keys (Optional[Sequence[str]]) – Candidate keys used to find reaction SMILES strings in each reaction record. The keys are tried in order.

  • template_keys (Optional[Sequence[str]]) – Candidate keys used to find rule or template strings in each reaction record. The keys are tried in order.

Returns:

Tuple of reaction SMILES list and template mapping.

Return type:

Tuple[List[str], Dict[str, str]]

Example#

extractor = KEGGExtractor()
data = extractor.build_module_json(
    "M00001",
    with_compounds=True,
    with_atom_maps=False,
)

abstractor = AbstractReactionExtractor()
reactions, templates = abstractor.extract_reactions_and_templates(
    data=data,
    reaction_id_keys=["id", "kegg_id", "rid"],
    reaction_smiles_keys=["smiles", "reaction", "rxn_smiles"],
    template_keys=["rule", "template", "smirks"],
)
iter_reaction_records(data: Mapping[str, Any]) Iterable[Tuple[Mapping[str, Any], str]][source]#

Iterate over reaction records from a module-like or pathway-like JSON block.

Supported structures include:

  • module-like: ``{“reactions”: […]}`

  • pathway-like: {"by_module": {"M00001": {"reactions": [...]}, ...}}

Parameters:

data (Mapping[str, Any]) – Input JSON-like mapping.

Yields:

Tuples of (reaction_record, module_id).

Return type:

Iterable[Tuple[Mapping[str, Any], str]]

Example#

abstractor = AbstractReactionExtractor()
for record, module_id in abstractor.iter_reaction_records(data):
    print(module_id, record.get("id"))
class synkit.CRN.Construct.abstract.AbstractReactionNetwork(molecule_pool: ~typing.List[str], reactions: ~typing.List[str], templates: ~typing.Dict[str, str] = <factory>, label_to_molecule: ~typing.Dict[str, str] = <factory>)[source]#

Bases: object

Symbolic abstraction of a reaction network.

Parameters:
  • molecule_pool (List[str]) – Unique molecule pool in the original full representation.

  • reactions (List[str]) – Abstract symbolic reactions such as "A+B>>C+D".

  • templates (Dict[str, str]) – Optional mapping from reaction identifiers to rule or template strings.

  • label_to_molecule (Dict[str, str]) – Mapping from abstract labels back to original molecule strings.

label_to_molecule: Dict[str, str]#
molecule_pool: List[str]#
reactions: List[str]#
save_json(path: str | Path, *, name: str | None = None) None[source]#

Save the abstract network as a JSON file.

Parameters:
  • path (PathLike) – Output JSON path.

  • name (Optional[str]) – Optional metadata name. If omitted, the filename stem is used.

Returns:

None

Return type:

None

Example#

network.save_json("abstract_network.json")
templates: Dict[str, str]#
to_dict() Dict[str, Any][source]#

Convert the abstract network to a plain dictionary.

Returns:

Dictionary representation of the abstract network.

Return type:

Dict[str, Any]

Example#

payload = network.to_dict()
to_json_payload(name: str = 'abstract_reaction_network') Dict[str, Any][source]#

Convert the abstract network into a SynKit-style JSON payload.

Parameters:

name (str) – Name stored in the metadata block.

Returns:

JSON-serializable payload.

Return type:

Dict[str, Any]

Example#

payload = network.to_json_payload(name="glycolysis_abstract")
synkit.CRN.Construct.abstract.deduplicate_abstract_reactions(reactions: Sequence[str]) List[str][source]#

Remove identity reactions and duplicate abstract reactions.

Reactant and product order are normalized internally before comparison. The original retained representative is the first encountered entry.

Parameters:

reactions (Sequence[str]) – Abstract reactions such as "A+B>>C+D".

Returns:

Filtered abstract reactions.

Return type:

List[str]

Example#

filtered = deduplicate_abstract_reactions(
    ["A+B>>C", "B+A>>C", "A>>A"]
)
synkit.CRN.Construct.arity.count_lhs_components(text: str) int | None[source]#
synkit.CRN.Construct.arity.infer_rule_arity(rule: Any) int[source]#
class synkit.CRN.Construct.builder.CRNExpand(rules: 'List[Any]', repeats: 'int' = 50, explicit_h: 'bool' = False, implicit_temp: 'bool' = False, strategy: 'Optional[str]' = None, keep_aam: 'bool' = True, max_components: 'int' = 3, use_frontier: 'bool' = True, max_mixtures_per_rule_step: 'int' = 50000, max_tasks_per_step: 'int' = 200000, allow_self_mixtures: 'bool' = False, skip_no_change: 'bool' = True, allow_empty_side: 'bool' = False, dedup_delta: 'bool' = True, dedup_across_rules: 'bool' = False)[source]#

Bases: object

allow_empty_side: bool = False#
allow_self_mixtures: bool = False#
build(seeds: Iterable[str], *, parallel: bool = False, max_workers: int | None = None, reset: bool = True) DiGraph[source]#
dedup_across_rules: bool = False#
dedup_delta: bool = True#
property derivation_records: List[Dict[str, object]]#
derivations: DerivationLog#
explicit_h: bool = False#
graph: DiGraph#
implicit_temp: bool = False#
keep_aam: bool = True#
max_components: int = 3#
max_mixtures_per_rule_step: int = 50000#
max_tasks_per_step: int = 200000#
repeats: int = 50#
reset() None[source]#
rules: List[Any]#
property rxn_nodes: List[int]#
skip_no_change: bool = True#
property species_nodes: List[int]#
state: DerivationState#
strategy: str | None = None#
strategy_engine: FrontierStrategy#
use_frontier: bool = True#
synkit.CRN.Construct.builder.build_crn_from_smarts(rules: List[str], seeds: List[str], *, repeats: int = 50, explicit_h: bool = False, implicit_temp: bool = False, strategy: str | None = None, keep_aam: bool = True, parallel: bool = False, max_workers: int | None = None, max_components: int = 3, use_frontier: bool = True, max_mixtures_per_rule_step: int = 50000, max_tasks_per_step: int = 200000, allow_self_mixtures: bool = False, skip_no_change: bool = True, allow_empty_side: bool = False, dedup_delta: bool = True, dedup_across_rules: bool = False) DiGraph[source]#
class synkit.CRN.Construct.derivation.DerivationLog(records: 'List[DerivationRecord]' = <factory>)[source]#

Bases: object

append(*, event_id: int, label: str, step: int, rule_index: int, reactants: Tuple[str, ...], products: Tuple[str, ...]) None[source]#
as_dicts() List[Dict[str, object]][source]#
clear() None[source]#
records: List[DerivationRecord]#
class synkit.CRN.Construct.derivation.DerivationRecord(event_id: int, label: str, step: int, rule_index: int, reactants: Tuple[str, ...], products: Tuple[str, ...])[source]#

Bases: object

Abstract direct derivation record.

This stores the reaction event as multisets of standardized species without changing the public NetworkX CRN representation.

event_id: int#
label: str#
products: Tuple[str, ...]#
reactants: Tuple[str, ...]#
rule_index: int#
step: int#
class synkit.CRN.Construct.flattener.ReactionDeltaFlattener(graph: 'nx.DiGraph', skip_no_change: 'bool' = True, allow_empty_side: 'bool' = False, deduplicate: 'bool' = True)[source]#

Bases: object

allow_empty_side: bool = False#
build() ReactionDeltaFlattener[source]#
deduplicate: bool = True#
graph: DiGraph#
property reactions: List[Dict[str, Any]]#
skip_no_change: bool = True#
synkit.CRN.Construct.keys.make_dedup_key(*, dedup_across_rules: bool, rule_index: int, r_keep_keys: Tuple[str, ...], p_keep_keys: Tuple[str, ...]) Tuple[int | None, Tuple[str, ...], Tuple[str, ...]][source]#
synkit.CRN.Construct.mixtures.iter_mixtures_arity1(pool_keys: List[str], frontier_keys: List[str], *, use_frontier: bool, cap: int) Iterator[Tuple[str, ...]][source]#
synkit.CRN.Construct.mixtures.iter_mixtures_arity2(pool_keys: List[str], frontier_keys: List[str], *, use_frontier: bool, allow_self_mixtures: bool, cap: int) Iterator[Tuple[str, ...]][source]#
synkit.CRN.Construct.mixtures.iter_mixtures_arityk(pool_keys: List[str], frontier_keys: List[str], *, use_frontier: bool, allow_self_mixtures: bool, arity: int, cap: int) Iterator[Tuple[str, ...]][source]#
synkit.CRN.Construct.smiles.assign_deterministic_maps_and_canonical(nomap_smiles: str) str | None[source]#
synkit.CRN.Construct.smiles.canonical_from_mol(mol: Any) str | None[source]#
synkit.CRN.Construct.smiles.has_atom_maps(mol: Any) bool[source]#
synkit.CRN.Construct.smiles.mol_from_smiles_safe(smiles: str) Any | None[source]#
synkit.CRN.Construct.smiles.sanitize_safe(mol: Any) bool[source]#
synkit.CRN.Construct.smiles.standardize_smiles_rdkit(smiles: str, *, keep_aam: bool) str | None[source]#

Standardize one SMILES string.

Behavior:
  • If RDKit is unavailable: passthrough.

  • If keep_aam=False: strip atom maps, remove Hs, return canonical SMILES.

  • If keep_aam=True:
    • keep mapped canonical SMILES if maps already exist

    • otherwise assign deterministic maps and return canonical mapped SMILES

synkit.CRN.Construct.smiles.strip_maps_and_canonical_from_mol(mol: Any) str | None[source]#
class synkit.CRN.Construct.state.DerivationState(pool_keys: Set[str] = <factory>, frontier_keys: Set[str] = <factory>, step: int = 0)[source]#

Bases: object

Lightweight builder state inspired by derivation-graph builders.

This keeps the active chemical universe separate from the graph object so the orchestration layer does not need to treat NetworkX as its working memory for frontier expansion.

advance(next_frontier: Set[str]) None[source]#
begin_step(step: int) None[source]#
frontier_keys: Set[str]#
pool_keys: Set[str]#
set_initial(*, pool_keys: Set[str], frontier_keys: Set[str]) None[source]#
step: int = 0#
class synkit.CRN.Construct.strategy.ConstructionStrategy(*args, **kwargs)[source]#

Bases: Protocol

iter_mixtures(*, pool_keys: List[str], frontier_keys: List[str], arity: int, use_frontier: bool, allow_self_mixtures: bool, cap: int, max_components: int) Iterator[Tuple[str, ...]][source]#
class synkit.CRN.Construct.strategy.FrontierStrategy[source]#

Bases: object

Default strategy with the same semantics as the validated monolith.

The purpose is not to change chemistry, only to separate the exploration strategy from the builder. This mirrors the derivation-graph idea of having an execution policy distinct from rule application.

iter_mixtures(*, pool_keys: List[str], frontier_keys: List[str], arity: int, use_frontier: bool, allow_self_mixtures: bool, cap: int, max_components: int) Iterator[Tuple[str, ...]][source]#
synkit.CRN.Construct.worker.apply_rule_worker(args: Tuple[int, Any, str, bool, bool, str | None, Tuple[str, ...]]) Tuple[int, Tuple[str, ...], List[str]][source]#

Apply one rule to one substrate mixture.

This intentionally preserves the behavior of the validated monolith: - automorphism=True - order-preserving deduplication of raw output strings

class synkit.CRN.Construct.DAG.crn.CRN(rule_list: List[Dict[str, Any]], smiles_list: str | Sequence[str], *, n_repeats: int = 3, prune: bool = True, strategy: str | Strategy = Strategy.BACKTRACK, verbosity: int = 0)[source]#

Bases: object

Expand an initial pool of molecules through several rounds of rule application using MODReactor under the hood.

Public attributes#

initial_smilesList[str]

The starting set of molecules.

n_repeatsint

Number of expansion rounds requested.

roundsList[Tuple[str, List[str]]]

[(“Round 1”, [rxn₁, …]), …] — kept for backwards compatibility.

final_smilesList[str]

Unique molecule SMILES present after the last round.

rule_countint

How many rules were supplied.

Public helpers#

run() -> CRN

Rebuild the network from scratch (chainable).

product_sets -> Dict[str, List[str]]

Mapping of round‑tag → reaction‑SMILES list.

get_reaction_smiles() -> Dict[str, List[str]]

Same as product_sets (alias).

help()

Human‑readable summary.

get_reaction_smiles() Dict[str, List[str]][source]#
help() None[source]#
property product_sets: Dict[str, List[str]]#

Dict view of the per‑round reaction SMILES.

Handles both shapes:

  • self.rounds == [{“Round 1”: […]}, {“Round 2”: […]}, …]

  • self.rounds == [(“Round 1”, […]), (“Round 2”, […]), …]

property rule_count: int#
run() CRN[source]#

Re‑run the expansion pipeline and return self for chaining.

class synkit.CRN.Construct.DAG.mod_crn.MODCRN(rule_db_path: str | List[str], initial_smiles: List[str], n_repeats: int = 2)[source]#

Bases: object

MODCRN ======

High-level class for constructing, inspecting, and reporting a chemical reaction network using the MØD derivation graph (DG) API.

Key Features#

  • Flexible rule loading: accept a JSON database path or a list of GML strings.

  • Initial molecule deduplication via graph isomorphism.

  • Customizable iterative strategy for rule applications.

  • Built-in summary and external report export.

Parameters#

rule_db_pathUnion[str, List[str]]

Path to a JSON rule database or list of GML rule strings.

initial_smilesList[str]

SMILES strings of the seed molecules.

repeatsint, default=2

Number of repeat cycles for rule application.

Properties#

rulesList[Rule]

Loaded Rule objects for network construction.

graphsList[Graph]

Deduplicated initial Graph objects.

derivation_graphDG

The active derivation graph instance.

num_verticesint

Number of molecules in the derivation graph.

num_edgesint

Number of reactions in the derivation graph.

Methods#

build() -> None

Populate the derivation graph with the configured strategy.

print_summary() -> None

Print and save a concise summary of the derivation graph.

export_report(path: str) -> None

Generate an external report via the mod_post CLI.

help() -> None

Print usage examples and API summarylog.

build() None[source]#

Populate the derivation graph using: addSubset(initial) >> repeat[repeats](rules)

property derivation_graph: None#

The active derivation graph instance.

export_report() None[source]#

Generate an external report via the mod_post CLI.

property graphs: List[None]#

Deduplicated initial Graph objects.

help() None[source]#

Print usage examples and API summary for MODCRN.

property num_edges: int#

Number of reactions in the derivation graph.

property num_vertices: int#

Number of molecules in the derivation graph.

print_summary() None[source]#

Print and save a concise summary of the derivation graph.

property rules: List[None]#

Loaded Rule objects for network construction.

class synkit.CRN.Construct.DAG.syncrn.ReactionDeltaFlattener(graph: 'nx.DiGraph', skip_no_change: 'bool' = True, allow_empty_side: 'bool' = False, deduplicate: 'bool' = True)[source]#

Bases: object

allow_empty_side: bool = False#
build() ReactionDeltaFlattener[source]#
deduplicate: bool = True#
graph: DiGraph#
property reactions: List[Dict[str, Any]]#
skip_no_change: bool = True#
class synkit.CRN.Construct.DAG.syncrn.SynCRN(rules: 'List[Any]', repeats: 'int' = 50, explicit_h: 'bool' = False, implicit_temp: 'bool' = False, strategy: 'Optional[str]' = None, keep_aam: 'bool' = True, max_components: 'int' = 3, use_frontier: 'bool' = True, max_mixtures_per_rule_step: 'int' = 50000, max_tasks_per_step: 'int' = 200000, skip_no_change: 'bool' = True, allow_empty_side: 'bool' = False, dedup_delta: 'bool' = True, dedup_across_rules: 'bool' = False)[source]#

Bases: object

allow_empty_side: bool = False#
build(seeds: Iterable[str], *, parallel: bool = False, max_workers: int | None = None) DiGraph[source]#
dedup_across_rules: bool = False#
dedup_delta: bool = True#
explicit_h: bool = False#
graph: DiGraph#
implicit_temp: bool = False#
keep_aam: bool = True#
max_components: int = 3#
max_mixtures_per_rule_step: int = 50000#
max_tasks_per_step: int = 200000#
repeats: int = 50#
rules: List[Any]#
property rxn_nodes: List[int]#
skip_no_change: bool = True#
property species_nodes: List[int]#
strategy: str | None = None#
use_frontier: bool = True#
synkit.CRN.Construct.DAG.syncrn.build_syncrn_from_smarts(rules: List[str], seeds: List[str], *, repeats: int = 50, explicit_h: bool = False, implicit_temp: bool = False, strategy: str | None = None, keep_aam: bool = True, parallel: bool = False, max_workers: int | None = None, max_components: int = 3, use_frontier: bool = True, max_mixtures_per_rule_step: int = 50000, max_tasks_per_step: int = 200000, skip_no_change: bool = True, allow_empty_side: bool = False, dedup_delta: bool = True, dedup_across_rules: bool = False) DiGraph[source]#

Structure#

class synkit.CRN.Structure.reaction.RXNSide(counts: Dict[str, int]=<factory>)[source]#

Bases: object

Stoichiometric multiset for one reaction side.

Parameters:

counts (Dict[str, int]) – Mapping species_id -> coefficient.

counts: Dict[str, int]#
get(species_id: str, default: int = 0) int[source]#

Get the coefficient for one species.

Parameters:
  • species_id (str) – Internal species id.

  • default (int) – Value to return when species is absent.

Returns:

Stoichiometric coefficient.

Return type:

int

items() List[Tuple[str, int]][source]#

Return the side as a list of (species_id, coeff) pairs.

Returns:

Side entries.

Return type:

List[Tuple[str, int]]

to_dict() Dict[str, int][source]#

Return a JSON-like dictionary representation.

Returns:

Species-to-coefficient mapping.

Return type:

Dict[str, int]

class synkit.CRN.Structure.reaction.Reaction(id: str, source_node_id: Hashable, source_kind: str, lhs: RXNSide, rhs: RXNSide, label: str | None = None, step: int | None = None, rule_index: int | None = None, app_index: int | None = None, rule_repr: str | None = None, rule_id: str | None = None, source_attrs: Dict[str, ~typing.Any]=<factory>, metadata: Dict[str, ~typing.Any]=<factory>, reactant_edge_attrs: Dict[str, ~typing.Dict[str, ~typing.Any]]=<factory>, product_edge_attrs: Dict[str, ~typing.Dict[str, ~typing.Any]]=<factory>)[source]#

Bases: object

Canonical concrete reaction instance.

Parameters:
  • id (str) – Stable internal reaction id such as r_1.

  • source_node_id (Hashable) – Original reaction-node id in the source graph.

  • source_kind (str) – Original source node kind, often "rule".

  • lhs (RXNSide) – Reactant multiset.

  • rhs (RXNSide) – Product multiset.

  • label (Optional[str]) – Optional reaction label.

  • step (Optional[int]) – Optional expansion or generation step.

  • rule_index (Optional[int]) – Optional original rule index.

  • app_index (Optional[int]) – Optional application index.

  • rule_repr (Optional[str]) – Optional original rule/template string.

  • rule_id (Optional[str]) – Optional associated abstract rule id.

  • source_attrs (Dict[str, Any]) – Exact original node attributes from the source graph.

  • metadata (Dict[str, Any]) – Extra canonical metadata.

  • reactant_edge_attrs (Dict[str, Dict[str, Any]]) – Original edge attributes for reactant arcs, keyed by internal species id.

  • product_edge_attrs (Dict[str, Dict[str, Any]]) – Original edge attributes for product arcs, keyed by internal species id.

app_index: int | None = None#
format(species_token: Callable[[str], str], *, include_id: bool = True, include_rule: bool = False, include_step: bool = False, arrow: str = '>>') str[source]#

Format the full reaction as text.

Parameters:
  • species_token (Callable[[str], str]) – Function mapping internal species ids to display text.

  • include_id (bool) – Whether to include the internal reaction id.

  • include_rule (bool) – Whether to include rule provenance.

  • include_step (bool) – Whether to include the step field.

  • arrow (str) – Arrow string used between sides.

Returns:

Human-readable reaction string.

Return type:

str

format_side(side: RXNSide, species_token: Callable[[str], str]) str[source]#

Format one reaction side as text.

Parameters:
  • side (RXNSide) – Left or right side.

  • species_token (Callable[[str], str]) – Function mapping internal species ids to display text.

Returns:

Human-readable reaction side.

Return type:

str

id: str#
label: str | None = None#
lhs: RXNSide#
metadata: Dict[str, Any]#
product_edge_attrs: Dict[str, Dict[str, Any]]#
reactant_edge_attrs: Dict[str, Dict[str, Any]]#
rhs: RXNSide#
rule_id: str | None = None#
rule_index: int | None = None#
rule_repr: str | None = None#
source_attrs: Dict[str, Any]#
source_kind: str#
source_node_id: Hashable#
step: int | None = None#
to_dict() Dict[str, Any][source]#

Return a JSON-like dictionary representation.

Returns:

Reaction as a dictionary.

Return type:

Dict[str, Any]

class synkit.CRN.Structure.rule.Rule(id: str, rule_index: int | None = None, rule_repr: str | None = None, label: str | None = None, metadata: Dict[str, ~typing.Any]=<factory>)[source]#

Bases: object

Abstract rule provenance shared by one or more concrete reactions.

This does not become a node in the bipartite CRN graph. Instead, reaction nodes may carry kind="rule" in the input graph while still being interpreted as concrete reaction instances that reference a rule record.

Parameters:
  • id (str) – Stable internal rule id such as rule_1.

  • rule_index (Optional[int]) – Optional original rule index.

  • rule_repr (Optional[str]) – Optional original rule/template string.

  • label (Optional[str]) – Optional human-readable rule label.

  • metadata (Dict[str, Any]) – Extra metadata for the rule.

id: str#
label: str | None = None#
metadata: Dict[str, Any]#
rule_index: int | None = None#
rule_repr: str | None = None#
property signature: Tuple[int | None, str | None]#

Signature used to deduplicate rules across reactions.

Returns:

(rule_index, rule_repr)

Return type:

Tuple[Optional[int], Optional[str]]

to_dict() Dict[str, Any][source]#

Return a JSON-like dictionary representation.

Returns:

Rule as a dictionary.

Return type:

Dict[str, Any]

class synkit.CRN.Structure.species.Species(id: str, source_node_id: Hashable, label: str, smiles: str | None = None, source_attrs: Dict[str, ~typing.Any]=<factory>, metadata: Dict[str, ~typing.Any]=<factory>)[source]#

Bases: object

Canonical species record.

Parameters:
  • id (str) – Stable internal species id such as s_1.

  • source_node_id (Hashable) – Original node id in the source NetworkX graph.

  • label (str) – Human-readable display label.

  • smiles (Optional[str]) – Optional SMILES string.

  • source_attrs (Dict[str, Any]) – Exact original node attributes from the source graph.

  • metadata (Dict[str, Any]) – Optional extra canonical metadata.

id: str#
label: str#
metadata: Dict[str, Any]#
smiles: str | None = None#
source_attrs: Dict[str, Any]#
source_node_id: Hashable#
to_dict() Dict[str, Any][source]#

Return a JSON-like dictionary representation.

Returns:

Species as a dictionary.

Return type:

Dict[str, Any]

class synkit.CRN.Structure.syncrn.SynCRN(species: Dict[str, ~synkit.CRN.Structure.species.Species]=<factory>, reactions: Dict[str, ~synkit.CRN.Structure.reaction.Reaction]=<factory>, rules: Dict[str, ~synkit.CRN.Structure.rule.Rule]=<factory>, graph_attrs: Dict[str, ~typing.Any]=<factory>, metadata: Dict[str, ~typing.Any]=<factory>)[source]#

Bases: object

Canonical reaction-system object for SynKit-CRN.

Official representations exposed by this object#

  • SynCRN: master reaction-system object

  • SynCRN.to_digraph(): species–reaction bipartite graph view

  • SynCRN.to_stoichiometric_matrices(): matrix view for stoichiometric analysis

  • SynCRN.to_petrinet(): pre/post incidence view for pathways

  • SynCRN.to_equations(): human-readable reaction list

Design notes#

Input digraph nodes with kind="rule" are preserved exactly on round-trip via Reaction.source_kind and Reaction.source_attrs. They are also normalized as concrete reaction instances for downstream computation.

param species:

Mapping from internal species ids to Species records.

type species:

Dict[str, Species]

param reactions:

Mapping from internal reaction ids to Reaction records.

type reactions:

Dict[str, Reaction]

param rules:

Mapping from internal rule ids to Rule records.

type rules:

Dict[str, Rule]

param graph_attrs:

Original graph-level attributes from the input digraph.

type graph_attrs:

Dict[str, Any]

param metadata:

Additional canonical metadata for the SynCRN object.

type metadata:

Dict[str, Any]

Example#

syn = SynCRN.from_reaction_strings(["A>>B", "B>>C"])
print(syn.n_species)
print(syn.to_equations())
describe(*, include_species: bool = False, species: str = 'label') str[source]#

Return a human-readable multiline description of the network.

Parameters:
  • include_species (bool) – Whether to append a final line listing species names.

  • species (str) – Species display mode used in the text summary.

Returns:

Multiline text description.

Return type:

str

Example#

print(syn.describe(include_species=True, species="label"))
format_reaction(reaction_id: str, *, species: str = 'label', include_id: bool = True, include_rule: bool = False, include_step: bool = False, arrow: str = '>>') str[source]#

Format one reaction as text.

Parameters:
  • reaction_id (str) – Internal reaction id.

  • species (str) – Species display mode.

  • include_id (bool) – Whether to include the internal reaction id.

  • include_rule (bool) – Whether to include rule provenance.

  • include_step (bool) – Whether to include step provenance.

  • arrow (str) – Arrow string between lhs and rhs.

Returns:

Human-readable reaction string.

Return type:

str

Example#

syn.format_reaction("r_1", species="label", include_rule=True)
classmethod from_digraph(crn: DiGraph, *, species_kind: str = 'species', reaction_kinds: Tuple[str, ...] = ('reaction', 'rule'), species_prefix: str = 's_', reaction_prefix: str = 'r_', rule_prefix: str = 'rule_', strict: bool = True) SynCRN[source]#

Build a canonical SynCRN object from a species–reaction bipartite digraph.

The current SynKit-CRN graph frequently stores concrete reaction-instance nodes with kind="rule". This constructor preserves that original kind in Reaction.source_kind while also converting such nodes into concrete reaction instances for downstream computation.

Parameters:
  • crn (nx.DiGraph) – Directed bipartite graph with species and reaction-like nodes.

  • species_kind (str) – Node-kind value used for species nodes.

  • reaction_kinds (Tuple[str, ...]) – Node-kind values used for reaction-instance nodes.

  • species_prefix (str) – Prefix for generated internal species ids.

  • reaction_prefix (str) – Prefix for generated internal reaction ids.

  • rule_prefix (str) – Prefix for generated internal rule ids.

  • strict (bool) – Whether malformed graph structure should raise an error.

Returns:

Canonical SynCRN object.

Return type:

SynCRN

Raises:

TypeError – If crn is not an nx.DiGraph.

Example#

syn = SynCRN.from_digraph(crn)
print(syn.to_equations())
classmethod from_reaction_strings(rxns: List[str], rules: List[str | None] | None = None, *, parser: Callable[[str], Any] | None = None, strict: bool = True) SynCRN[source]#

Build a SynCRN object directly from reaction strings.

Reactions and rules are interpreted pairwise, so rxns[i] corresponds to rules[i].

ID policy#

This constructor uses plain numeric string ids instead of prefixed ids.

  • Species ids: "1", "2", …

  • Reaction ids: continue after species ids

  • Rule ids: "1", "2", … within the separate rule table

Species are indexed by first appearance in the input reactions.

param rxns:

List of reaction strings such as "2A>>B+3C".

type rxns:

List[str]

param rules:

Optional list of rule strings pairwise aligned with rxns.

type rules:

Optional[List[Optional[str]]]

param parser:

Optional side parser. It should accept one side string such as "2A+B" and return either a mapping, an object with to_dict(), or an object with items().

type parser:

Optional[Callable[[str], Any]]

param strict:

Whether malformed reaction strings or empty sides should raise an error.

type strict:

bool

returns:

Canonical SynCRN object.

rtype:

SynCRN

raises TypeError:

If rxns or rules have invalid types.

raises ValueError:

If reaction strings are malformed or rules are not pairwise aligned.

Example#

syn = SynCRN.from_reaction_strings(["2A>>B+3C"])

syn = SynCRN.from_reaction_strings(
    ["A+B>>C", "C>>D"],
    rules=["rule_1", "rule_2"],
    parser=RXNSide.from_str,
)
graph_attrs: Dict[str, Any]#
metadata: Dict[str, Any]#
property n_reactions: int#

Return the number of reactions.

Returns:

Number of reactions.

Return type:

int

property n_rules: int#

Return the number of unique abstract rules.

Returns:

Number of rules.

Return type:

int

property n_species: int#

Return the number of species.

Returns:

Number of species.

Return type:

int

property reaction_ids: List[str]#

Return the internal reaction order.

Returns:

Ordered list of reaction ids.

Return type:

List[str]

Example#

print(syn.reaction_ids)
reactions: Dict[str, Reaction]#
property rule_ids: List[str]#

Return the internal rule order.

Returns:

Ordered list of rule ids.

Return type:

List[str]

Example#

print(syn.rule_ids)
rules: Dict[str, Rule]#
species: Dict[str, Species]#
property species_ids: List[str]#

Return the internal species order.

Returns:

Ordered list of species ids.

Return type:

List[str]

Example#

print(syn.species_ids)
to_dict() Dict[str, Any][source]#

Return a nested JSON-like dictionary representation.

Returns:

Full SynCRN object as a dictionary.

Return type:

Dict[str, Any]

Example#

data = syn.to_dict()
print(data["species"].keys())
to_digraph(*, node_ids: str = 'source', reaction_kind: str | None = None, include_internal_ids: bool = True) DiGraph[source]#

Reconstruct a species–reaction bipartite digraph.

By default, this method preserves original node ids and original reaction-node kinds. This means that input reaction nodes with kind="rule" will still appear as kind="rule" after round-trip.

Parameters:
  • node_ids (str) – "source" preserves original node ids, while "internal" uses canonical ids such as s_1 and r_1.

  • reaction_kind (Optional[str]) – Optional override for reconstructed reaction-node kind.

  • include_internal_ids (bool) – Whether to attach syncrn_id and source_node_id as node attributes.

Returns:

Reconstructed bipartite digraph.

Return type:

nx.DiGraph

Raises:

ValueError – If node_ids is not "source" or "internal".

Example#

g2 = syn.to_digraph()
g3 = syn.to_digraph(node_ids="internal", reaction_kind="reaction")
to_equations(*, species: str = 'label', include_id: bool = True, include_rule: bool = False, include_step: bool = False, arrow: str = '>>') List[str][source]#

Return the network as a list of formatted reaction equations.

Parameters:
  • species (str) – Species display mode.

  • include_id (bool) – Whether to include internal reaction ids.

  • include_rule (bool) – Whether to include rule provenance.

  • include_step (bool) – Whether to include step provenance.

  • arrow (str) – Arrow string between lhs and rhs.

Returns:

List of formatted reaction equations.

Return type:

List[str]

Example#

eqs = syn.to_equations(species="smiles", include_rule=True)
print("\n".join(eqs))
to_petrinet() Dict[str, Any][source]#

Return a Petri-net style pre/post incidence view.

The returned dictionary contains:

  • places: species ids

  • transitions: reaction ids

  • pre: input incidence map

  • post: output incidence map

Returns:

Petri-net incidence representation.

Return type:

Dict[str, Any]

Example#

pn = syn.to_petrinet()
print(pn["pre"])
print(pn["post"])
to_stoichiometric_matrices() Dict[str, Any][source]#

Construct stoichiometric matrices in canonical species and reaction order.

The returned dictionary contains:

  • species_order

  • reaction_order

  • S_minus: reactant-incidence matrix

  • S_plus: product-incidence matrix

  • S: net stoichiometric matrix

Returns:

Stoichiometric matrix view of the network.

Return type:

Dict[str, Any]

Example#

mats = syn.to_stoichiometric_matrices()
print(mats["species_order"])
print(mats["reaction_order"])
print(mats["S"])

Pathway#

class synkit.CRN.Pathway.pathfinder.PathFinderConfig(max_depth: int = 12, max_paths: int = 20, stop_after_first: bool = False, deduplicate_by_flow: bool = True)[source]#

Bases: object

Configuration for qualitative pathway search.

This configuration controls the breadth-first search over qualitative set-semantics states.

Parameters:
  • max_depth (int) – Maximum number of reaction firings allowed in a candidate pathway.

  • max_paths (int) – Maximum number of pathway candidates to return.

  • stop_after_first (bool) – Whether to stop the search immediately after the first accepted candidate is found.

  • deduplicate_by_flow (bool) – Whether to deduplicate candidates by their reaction-count flow vector rather than retaining multiple sequences with the same aggregate flow.

deduplicate_by_flow: bool = True#
max_depth: int = 12#
max_paths: int = 20#
stop_after_first: bool = False#
class synkit.CRN.Pathway.pathfinder.PathwayCandidate(reactions: List[str], flow: Dict[str, int], reached_species: List[str], depth: int, realizable: bool | None = None, certificate: List[str] | None = None)[source]#

Bases: object

One qualitative pathway candidate returned by PathwayFinder.

A candidate stores both the ordered reaction sequence used during qualitative search and the corresponding aggregated reaction-count flow.

Parameters:
  • reactions (List[str]) – Ordered list of reaction ids in the candidate sequence.

  • flow (Dict[str, int]) – Aggregated reaction firing counts derived from reactions.

  • reached_species (List[str]) – Sorted list of species reachable after firing the candidate sequence in qualitative set semantics.

  • depth (int) – Length of the reaction sequence.

  • realizable (Optional[bool]) – Optional exact realizability verdict computed afterwards from Petri-net semantics.

  • certificate (Optional[List[str]]) – Optional firing certificate returned by exact realizability checking.

certificate: List[str] | None = None#
depth: int#
flow: Dict[str, int]#
reached_species: List[str]#
reactions: List[str]#
realizable: bool | None = None#
class synkit.CRN.Pathway.pathfinder.PathwayFinder(config: PathFinderConfig | None = None)[source]#

Bases: object

Qualitative source-to-target pathway search for SynCRN-like inputs.

This class searches in set semantics: a reaction is usable once all its reactant species are present in the current available set, and firing it adds its product species to that set.

Species are not consumed during the qualitative search. Exact stoichiometric and token-based validation can be applied afterwards using validate_candidates().

edges: Dict[str, Tuple[Dict[str, int], Dict[str, int]]]#
find_paths_set(*, source_species: Iterable[str], target_species: Iterable[str], max_depth: int | None = None, max_paths: int | None = None, stop_after_first: bool | None = None, deduplicate_by_flow: bool | None = None) List[PathwayCandidate][source]#

Find qualitative source-to-target pathways using set semantics.

The search is performed by breadth-first expansion over reachable species sets. At each step, enabled reactions add their product species to the current set without consuming reactants.

Parameters:
  • source_species (Iterable[str]) – Initial source species assumed to be present.

  • target_species (Iterable[str]) – Target species that must all be contained in the reached set.

  • max_depth (Optional[int]) – Optional override for maximum search depth. If None, the value from the configuration is used.

  • max_paths (Optional[int]) – Optional override for maximum number of returned candidates. If None, the value from the configuration is used.

  • stop_after_first (Optional[bool]) – Optional override controlling whether to stop after the first accepted candidate.

  • deduplicate_by_flow (Optional[bool]) – Optional override controlling whether candidates are deduplicated by aggregate flow.

Returns:

List of qualitative pathway candidates satisfying the target condition.

Return type:

List[PathwayCandidate]

Raises:
load_hypergraph(vertices: Iterable[str], edges: Mapping[str, Tuple[Mapping[str, int], Mapping[str, int]]]) PathwayFinder[source]#

Load a qualitative reaction hypergraph directly.

The hypergraph is represented by a set of species vertices and a mapping from reaction ids to (tail, head) multisets, where tail is the reactant side and head is the product side.

Parameters:
  • vertices (Iterable[str]) – Species identifiers in the hypergraph.

  • edges (Mapping[str, Tuple[Mapping[str, int], Mapping[str, int]]]) – Mapping from reaction id to a pair (tail, head) of multisets. Coefficients less than or equal to zero are ignored.

Returns:

The current finder instance.

Return type:

PathwayFinder

load_syncrn(crn: object, *, species: str = 'label', reaction: str = 'id') PathwayFinder[source]#

Load a SynCRN-like object through its incidence representation.

The CRN is tokenized into species and reaction identifiers suitable for qualitative search.

Parameters:
  • crn (object) – SynCRN-like object to load.

  • species (str) – Species naming mode passed to the tokenizer, for example "label" or "id".

  • reaction (str) – Reaction naming mode passed to the tokenizer, for example "id" or another supported tokenization key.

Returns:

The current finder instance.

Return type:

PathwayFinder

reaction_id_to_token: Dict[str, str]#
reaction_token_to_id: Dict[str, str]#
species_id_to_token: Dict[str, str]#
species_token_to_id: Dict[str, str]#
validate_candidates(crn: object, candidates: List[PathwayCandidate], *, initial_marking: Mapping[str, int], species: str = 'label', reaction: str = 'id') List[PathwayCandidate][source]#

Validate qualitative candidates by exact Petri-net realizability.

For each candidate, the aggregated reaction-count flow is checked using PathwayRealizability. The returned candidates preserve the original qualitative information and add realizability metadata.

Parameters:
  • crn (object) – SynCRN-like object used for exact validation.

  • candidates (List[PathwayCandidate]) – Qualitative candidates to validate.

  • initial_marking (Mapping[str, int]) – Initial place marking used for exact realizability checking.

  • species (str) – Species naming mode passed through to PathwayRealizability.load_syncrn_and_flow().

  • reaction (str) – Reaction naming mode passed through to PathwayRealizability.load_syncrn_and_flow().

Returns:

New list of candidates augmented with realizability verdicts and certificates.

Return type:

List[PathwayCandidate]

vertices: Set[str]#
synkit.CRN.Pathway.pathfinder.run_pathfinder_from_syncrn(crn: object, *, source_species: Iterable[str], target_species: Iterable[str], initial_marking: Mapping[str, int] | None = None, species: str = 'label', reaction: str = 'id', max_depth: int = 12, max_paths: int = 20, validate: bool = False, verbose: bool = True) List[PathwayCandidate][source]#

Convenience harness for qualitative pathway search on a SynCRN object.

This helper constructs a PathwayFinder, loads the CRN, runs qualitative search, and optionally validates the returned candidates by exact realizability.

Parameters:
  • crn (object) – SynCRN-like object to analyze.

  • source_species (Iterable[str]) – Initial source species assumed to be present.

  • target_species (Iterable[str]) – Target species that must all be reachable.

  • initial_marking (Optional[Mapping[str, int]]) – Optional initial marking used only when validate=True.

  • species (str) – Species naming mode used when tokenizing the CRN.

  • reaction (str) – Reaction naming mode used when tokenizing the CRN.

  • max_depth (int) – Maximum qualitative search depth.

  • max_paths (int) – Maximum number of pathway candidates to return.

  • validate (bool) – Whether to validate candidates by exact Petri-net realizability.

  • verbose (bool) – Whether to print a simple textual summary of the returned candidates.

Returns:

List of qualitative pathway candidates, optionally enriched with exact realizability results.

Return type:

List[PathwayCandidate]

Raises:

ValueError – If validate=True but initial_marking is not provided.

class synkit.CRN.Pathway.reachability.PathwayReachability(config: ReachabilityConfig | None = None)[source]#

Bases: object

Forward reachability utilities for SynCRN pathway analysis.

This class provides layered forward propagation over a reaction hypergraph. It supports two related semantics:

  • Set semantics: a reaction is enabled once all reactant species are present in the reachable set; stoichiometric multiplicities are ignored for enabling.

  • Multiset semantics: a reaction is enabled only when the current marking contains enough copies of each reactant species to satisfy stoichiometric coefficients.

The class can be loaded either from tokenized vertices / edges data or directly from a SynCRN-like object via load_syncrn().

Internally, reactions are stored as a mapping

reaction_id -> (tail_multiset, head_multiset)

where the tail is the reactant multiset and the head is the product multiset.

Parameters:

config (Optional[ReachabilityConfig]) – Optional reachability configuration. If omitted, a default ReachabilityConfig is used.

Example#

rr = PathwayReachability()
rr.load_hypergraph(
    vertices=["A", "B", "C", "D"],
    edges={
        "r1": ({"A": 1, "B": 1}, {"C": 1}),
        "r2": ({"C": 1}, {"D": 1}),
    },
)

result = rr.compute_layers_set(initial_species=["A", "B"])
print(result.species_first_depth)
# {'A': 0, 'B': 0, 'C': 1, 'D': 2}
compute_layers_multiset(initial_marking: Mapping[str, int], max_layers: int | None = None) ReachabilityResult[source]#

Compute layered forward reachability in multiset semantics.

In this mode, species counts matter. A reaction is enabled only if the current marking contains enough multiplicity for every reactant. At each layer, all currently enabled reactions are fired once in batch.

This procedure is useful when approximate token-flow behavior is desired, but it should not be confused with exhaustive Petri-net reachability analysis over all possible firing sequences.

Parameters:
  • initial_marking (Mapping[str, int]) – Initial species marking.

  • max_layers (Optional[int]) – Optional layer cap overriding the instance configuration.

Returns:

Reachability result containing the full layered traversal trace.

Return type:

ReachabilityResult

Example#

rr = PathwayReachability().load_hypergraph(
    vertices=["A", "B", "C"],
    edges={
        "r1": ({"A": 2}, {"B": 1}),
        "r2": ({"B": 1}, {"C": 1}),
    },
)

result = rr.compute_layers_multiset(initial_marking={"A": 2})

print(result.species_first_depth)
# {'A': 0, 'B': 1, 'C': 2}
compute_layers_set(initial_species: Iterable[str], max_layers: int | None = None) ReachabilityResult[source]#

Compute layered forward reachability in set semantics.

In this mode, only species presence matters. Stoichiometric multiplicities are ignored when deciding whether a reaction is enabled.

The algorithm proceeds layer by layer: 1. find all reactions whose reactants are already reachable, 2. keep only reactions not previously seen as enabled, 3. collect all products they produce, 4. add any newly produced species to the reachable set.

Parameters:
  • initial_species (Iterable[str]) – Initial set of reachable species.

  • max_layers (Optional[int]) – Optional layer cap overriding the instance configuration.

Returns:

Reachability result containing the full layered traversal trace.

Return type:

ReachabilityResult

Example#

rr = PathwayReachability().load_hypergraph(
    vertices=["A", "B", "C", "D"],
    edges={
        "r1": ({"A": 1, "B": 1}, {"C": 1}),
        "r2": ({"C": 1}, {"D": 1}),
    },
)

result = rr.compute_layers_set(initial_species=["A", "B"])

for layer in result.layers:
    print(layer.depth, layer.newly_reachable_species)

# 1 ['C']
# 2 ['D']
export_layers_json(result: ReachabilityResult, fn: str) PathwayReachability[source]#

Export a reachability result to a JSON file.

The output contains the initial species set, first-depth maps, and the full list of layered traversal records.

Parameters:
Returns:

The current instance, to allow fluent chaining.

Return type:

PathwayReachability

Raises:

OSError – Raised if the target file cannot be written.

Example#

rr.export_layers_json(result, "reachability_layers.json")
load_hypergraph(vertices: Iterable[str], edges: Mapping[str, Tuple[Mapping[str, int], Mapping[str, int]]]) PathwayReachability[source]#

Load a tokenized reaction hypergraph directly.

Each edge must map a reaction identifier to a pair (tail_multiset, head_multiset), where both multisets map species identifiers to strictly positive stoichiometric coefficients.

Non-positive coefficients are discarded during normalization.

Parameters:
  • vertices (Iterable[str]) – Iterable of species identifiers.

  • edges (Mapping[str, Tuple[Mapping[str, int], Mapping[str, int]]]) – Mapping from reaction identifier to (reactant_multiset, product_multiset).

Returns:

The current instance, to allow fluent chaining.

Return type:

PathwayReachability

Example#

rr = PathwayReachability().load_hypergraph(
    vertices=["A", "B", "C"],
    edges={
        "r1": ({"A": 1}, {"B": 1}),
        "r2": ({"B": 1}, {"C": 1}),
    },
)
load_syncrn(crn: object, *, species: str = 'label', reaction: str = 'id') PathwayReachability[source]#

Load reachability data from a SynCRN-like object.

This method delegates tokenization to tokenize_syncrn_incidence(), then stores both the tokenized hypergraph and the forward/backward token-id lookup tables.

Parameters:
  • crn (object) – SynCRN-like object to tokenize.

  • species (str) – Species attribute used during tokenization, such as "label" or another species node attribute supported by the adapter.

  • reaction (str) – Reaction attribute used during tokenization, such as "id".

Returns:

The current instance, to allow fluent chaining.

Return type:

PathwayReachability

Example#

rr = PathwayReachability().load_syncrn(
    syncrn_object,
    species="label",
    reaction="id",
)
class synkit.CRN.Pathway.reachability.ReachabilityConfig(max_layers: int = 10000, stop_when_no_new_species: bool = True)[source]#

Bases: object

Configuration for forward reachability traversal.

This configuration controls how many propagation layers are explored and whether the traversal should terminate as soon as no newly reachable species are discovered.

Parameters:
  • max_layers (int) – Maximum number of forward layers to compute.

  • stop_when_no_new_species (bool) – If True, stop once a layer produces no newly reachable species, even if reactions are still enabled.

Example#

cfg = ReachabilityConfig(
    max_layers=100,
    stop_when_no_new_species=True,
)
max_layers: int = 10000#
stop_when_no_new_species: bool = True#
class synkit.CRN.Pathway.reachability.ReachabilityLayer(depth: int, newly_enabled_reactions: List[str], newly_reachable_species: List[str], all_reachable_species: List[str])[source]#

Bases: object

One forward reachability layer.

A layer summarizes what became newly active at a given traversal depth. In set semantics, a reaction is considered enabled when all of its reactant species are already reachable. In multiset semantics, a reaction is enabled when the current marking contains sufficient multiplicity for each reactant.

Parameters:
  • depth (int) – Layer index, starting at 1 for the first propagation step.

  • newly_enabled_reactions (List[str]) – Reaction identifiers that became enabled at this layer.

  • newly_reachable_species (List[str]) – Species that became reachable for the first time at this layer.

  • all_reachable_species (List[str]) – Complete set of reachable species after this layer is applied.

Example#

layer = ReachabilityLayer(
    depth=2,
    newly_enabled_reactions=["r3", "r4"],
    newly_reachable_species=["E", "F"],
    all_reachable_species=["A", "B", "C", "D", "E", "F"],
)
all_reachable_species: List[str]#
depth: int#
newly_enabled_reactions: List[str]#
newly_reachable_species: List[str]#
class synkit.CRN.Pathway.reachability.ReachabilityResult(initial_species: List[str], layers: List[ReachabilityLayer], species_first_depth: Dict[str, int], reaction_first_depth: Dict[str, int])[source]#

Bases: object

Container for forward reachability results.

This object stores the initial support, the layered traversal trace, and the first depth at which each species or reaction became reachable or enabled.

Parameters:
  • initial_species (List[str]) – Initial reachable species support used to seed the traversal.

  • layers (List[ReachabilityLayer]) – Ordered list of reachability layers.

  • species_first_depth (Dict[str, int]) – Mapping from species identifier to the first layer depth at which that species became reachable. Initial species are assigned depth 0.

  • reaction_first_depth (Dict[str, int]) – Mapping from reaction identifier to the first layer depth at which that reaction became enabled.

Example#

result = ReachabilityResult(
    initial_species=["A", "B"],
    layers=[],
    species_first_depth={"A": 0, "B": 0},
    reaction_first_depth={},
)
initial_species: List[str]#
layers: List[ReachabilityLayer]#
reaction_first_depth: Dict[str, int]#
species_first_depth: Dict[str, int]#
synkit.CRN.Pathway.reachability.run_reachability_from_syncrn(crn: object, initial_species: Iterable[str], *, species: str = 'label', reaction: str = 'id', verbose: bool = True) Tuple[PathwayReachability, ReachabilityResult][source]#

Run layered qualitative reachability directly from a SynCRN-like object.

This convenience function constructs a PathwayReachability instance, loads the tokenized SynCRN representation, computes set-based layered reachability, and optionally prints a human-readable traversal summary.

Parameters:
  • crn (object) – SynCRN-like object to analyze.

  • initial_species (Iterable[str]) – Initial reachable species set.

  • species (str) – Species attribute used during tokenization.

  • reaction (str) – Reaction attribute used during tokenization.

  • verbose (bool) – If True, print the tokenized edges and each traversal layer.

Returns:

Pair (reachability_engine, result).

Return type:

Tuple[PathwayReachability, ReachabilityResult]

Example#

rr, result = run_reachability_from_syncrn(
    syncrn_object,
    initial_species=["A", "B"],
    species="label",
    reaction="id",
    verbose=True,
)
synkit.CRN.Pathway.reachability.syncrn_to_reachability_inputs(crn: object, *, species: str = 'label', reaction: str = 'id') Tuple[List[str], Dict[str, Tuple[Dict[str, int], Dict[str, int]]]][source]#

Convert a SynCRN-like object into tokenized reachability inputs.

This is a lightweight adapter returning only the tokenized species list and reaction hyperedges needed by PathwayReachability.

Parameters:
  • crn (object) – SynCRN-like object to tokenize.

  • species (str) – Species attribute used during tokenization.

  • reaction (str) – Reaction attribute used during tokenization.

Returns:

Pair (vertices, edges) where vertices is the species token list and edges maps reaction token to (tail_multiset, head_multiset).

Return type:

Tuple[List[str], Dict[str, Tuple[Dict[str, int], Dict[str, int]]]]

Example#

vertices, edges = syncrn_to_reachability_inputs(
    syncrn_object,
    species="label",
    reaction="id",
)
class synkit.CRN.Pathway.realizability.PathwayRealizability(config: RealizabilityConfig | None = None)[source]#

Bases: object

Exact flow-realizability utilities for SynCRN-like inputs.

A pathway flow is realizable if there exists an ordering of reaction firings such that:

  • each selected reaction is fired exactly the requested number of times,

  • the execution starts from the supplied initial marking,

  • every firing respects stoichiometric token consumption and production.

Unspecified reactions default to flow 0.

The class supports:

  • loading directly from tokenized hypergraph-style inputs,

  • loading from a SynCRN-like object,

  • exact bounded BFS realizability testing,

  • a sufficient acyclicity test via a König-style construction,

  • scaled realizability,

  • borrow realizability.

Parameters:

config (Optional[RealizabilityConfig]) – Optional configuration for bounded realizability search. If None, a default RealizabilityConfig is used.

Example#

pr = PathwayRealizability().load_syncrn_and_flow(
    syn,
    flow={"12": 1, "13": 1},
    species="label",
    reaction="id",
)
pr.build_petri_net_from_flow()
ok, cert = pr.is_realizable()
print(ok, cert)
build_petri_net_from_flow() PathwayRealizability[source]#

Build an augmented Petri net encoding the requested pathway flow.

For every active reaction eid with requested flow f > 0, two auxiliary places are created:

  • __ext__{eid}: supply place initialized with f tokens,

  • __target__{eid}: target place expected to accumulate f tokens.

The reaction transition consumes one token from the supply place on each firing and produces one token in the target place on each firing. This enforces exact realization of the requested number of firings.

Returns:

The current instance.

Return type:

PathwayRealizability

Raises:
  • RuntimeError – If no pathway data has been loaded.

  • ValueError – If a negative flow value is encountered.

Example#

pr = PathwayRealizability().load_syncrn_and_flow(
    syn,
    flow={"12": 1, "13": 1},
)
pr.build_petri_net_from_flow()
print(pr.initial_marking)
print(pr.goal_exact)
property certificate: List[str] | None#

Return the most recently found firing certificate.

Returns:

Realizing firing sequence, or None if none is cached.

Return type:

Optional[List[TransitionId]]

export_pnml(fn: str) PathwayRealizability[source]#

Export the current augmented Petri net to a JSON-based PNML-like file.

The exported structure contains places, transitions, initial marking, and active goal constraints. Despite the method name, the file written here is JSON rather than XML PNML.

Parameters:

fn (str) – Output filename.

Returns:

The current instance.

Return type:

PathwayRealizability

Example#

pr.export_pnml("pathway_realizability.json")
property goal_atleast: Dict[str, int]#

Return lower-bound target marking constraints.

Returns:

Lower-bound goal marking constraints.

Return type:

Dict[Place, int]

property goal_exact: Dict[str, int]#

Return exact target marking constraints.

Returns:

Exact goal marking constraints.

Return type:

Dict[Place, int]

property initial_marking: Dict[str, int]#

Return the active initial marking of the augmented Petri net.

Returns:

Initial marking.

Return type:

Dict[Place, int]

Raises:

RuntimeError – If the initial marking has not yet been initialized.

is_borrow_realizable(max_borrow_each: int = 2) Tuple[bool, Mapping[str, int] | None][source]#

Test realizability when temporary borrowed initial tokens are allowed.

Every combination of per-species borrowed tokens from 0 up to max_borrow_each is tried. For a candidate borrow multiset, the borrowed tokens are added to the initial marking and then imposed again as lower-bound final goals in goal_atleast so that the borrowed material must be returned.

Parameters:

max_borrow_each (int) – Maximum borrowed amount tested independently for each species.

Returns:

Pair (success, borrow) where borrow is the first successful borrow multiset, or None if no tested borrow succeeds.

Return type:

Tuple[bool, Optional[Mapping[str, int]]]

Example#

ok, borrow = pr.is_borrow_realizable(max_borrow_each=1)
print(ok, borrow)
is_realizable(max_states: int | None = None, max_depth: int | None = None) Tuple[bool, List[str] | None][source]#

Test exact realizability by bounded breadth-first search.

The search explores reachable Petri-net markings while recording firing sequences. A certificate is returned when a goal-satisfying marking is found.

Parameters:
  • max_states (Optional[int]) – Optional override for the maximum number of explored states.

  • max_depth (Optional[int]) – Optional override for the maximum explored firing depth.

Returns:

Pair (is_realizable, certificate) where certificate is a realizing transition sequence if one is found.

Return type:

Tuple[bool, Optional[List[TransitionId]]]

Example#

ok, cert = pr.is_realizable(max_states=50000, max_depth=2000)
print(ok)
print(cert)
is_realizable_via_konig() bool[source]#

Apply a König-style sufficient acyclicity test.

A directed bipartite dependency graph is built using:

  • species vertices ("v", species)

  • active-reaction vertices ("e", reaction)

with edges:

  • species -> reaction for reactant incidence,

  • reaction -> species for product incidence.

If this dependency graph is acyclic, the active flow is certified realizable by this sufficient test.

Returns:

True if the sufficient acyclicity condition holds, else False.

Return type:

bool

Example#

if pr.is_realizable_via_konig():
    print("Guaranteed realizable by sufficient test")
is_scaled_realizable(k_max: int = 4) Tuple[bool, int | None][source]#

Test whether a scaled version of the requested flow is realizable.

For each integer k from 1 to k_max, the requested flow is scaled to k * flow and tested for exact realizability.

Parameters:

k_max (int) – Maximum scale factor to try.

Returns:

Pair (success, k) where k is the first successful scale factor, or None if no tested scale succeeds.

Return type:

Tuple[bool, Optional[int]]

Example#

ok, k = pr.is_scaled_realizable(k_max=5)
print(ok, k)
load_hypergraph_and_flow(vertices: Iterable[str], edges: Mapping[str, Tuple[Mapping[str, int], Mapping[str, int]]], flow: Mapping[str, int], *, initial_marking: Mapping[str, int] | None = None) PathwayRealizability[source]#

Load tokenized hypergraph data and a requested pathway flow.

The edges mapping is interpreted as reaction_id -> (tail_multiset, head_multiset). Reactions not present in flow default to 0. Negative flow values are excluded here and validated again later during Petri-net construction.

Parameters:
  • vertices (Iterable[str]) – Iterable of species tokens.

  • edges (Mapping[str, Tuple[Mapping[str, int], Mapping[str, int]]]) – Mapping from reaction token to (tail, head) multisets.

  • flow (Mapping[str, int]) – Requested reaction firing counts.

  • initial_marking (Optional[Mapping[str, int]]) – Optional initial species marking.

Returns:

The current instance.

Return type:

PathwayRealizability

Example#

pr = PathwayRealizability().load_hypergraph_and_flow(
    vertices=["A", "B", "C"],
    edges={
        "r1": ({"A": 1}, {"B": 1}),
        "r2": ({"B": 1}, {"C": 1}),
    },
    flow={"r1": 1, "r2": 1},
    initial_marking={"A": 1},
)
load_syncrn_and_flow(crn: object, flow: Mapping[str, int] | None = None, *, initial_marking: Mapping[str, int] | None = None, species: str = 'label', reaction: str = 'id') PathwayRealizability[source]#

Load a SynCRN-like object together with a requested pathway flow.

The SynCRN object is tokenized via tokenize_syncrn_incidence(). User-supplied flow and marking keys are resolved flexibly against token, internal id, label, and source node id.

Parameters:
  • crn (object) – SynCRN-like object.

  • flow (Optional[Mapping[str, int]]) – Requested reaction firing counts.

  • initial_marking (Optional[Mapping[str, int]]) – Optional initial species marking.

  • species (str) – Species tokenization mode.

  • reaction (str) – Reaction tokenization mode.

Returns:

The current instance.

Return type:

PathwayRealizability

Example#

pr = PathwayRealizability().load_syncrn_and_flow(
    syn,
    flow={"12": 1, "13": 1},
    initial_marking={"A": 2},
    species="label",
    reaction="id",
)
property petri: PetriNet#

Return the active Petri net.

Returns:

Augmented Petri net for realizability checking.

Return type:

PetriNet

Raises:

RuntimeError – If the Petri net has not yet been built.

set_initial_marking(marking: Mapping[str, int]) PathwayRealizability[source]#

Replace the user-provided initial marking.

This resets any previously built Petri-net instance, goals, and cached firing certificate.

Parameters:

marking (Mapping[str, int]) – New initial marking.

Returns:

The current instance.

Return type:

PathwayRealizability

summary() RealizabilitySummary[source]#

Return a compact summary of the current realizability instance.

Returns:

Serializable instance summary.

Return type:

RealizabilitySummary

Example#

info = pr.summary()
print(info.active_flow)
class synkit.CRN.Pathway.realizability.RealizabilityConfig(max_states: int = 100000, max_depth: int = 10000)[source]#

Bases: object

Configuration for bounded realizability search.

Parameters:
  • max_states (int) – Maximum number of BFS states explored during exact realizability search.

  • max_depth (int) – Maximum firing-sequence depth explored during exact realizability search.

Example#

cfg = RealizabilityConfig(
    max_states=200_000,
    max_depth=5_000,
)
max_depth: int = 10000#
max_states: int = 100000#
class synkit.CRN.Pathway.realizability.RealizabilitySummary(n_species: int, n_reactions: int, active_flow: Dict[str, int]=<factory>, initial_marking: Dict[str, int]=<factory>, goal_exact: Dict[str, int]=<factory>, goal_atleast: Dict[str, int]=<factory>)[source]#

Bases: object

Small serializable summary of the active realizability instance.

Parameters:
  • n_species (int) – Number of species currently loaded in the instance.

  • n_reactions (int) – Number of reactions currently loaded in the instance.

  • active_flow (Dict[str, int]) – Active reaction flow restricted to reactions with positive requested firing count.

  • initial_marking (Dict[str, int]) – Initial marking supplied by the user before Petri-net augmentation.

  • goal_exact (Dict[str, int]) – Exact target marking constraints currently imposed on the auxiliary Petri-net places.

  • goal_atleast (Dict[str, int]) – Lower-bound target marking constraints currently imposed on the auxiliary Petri-net places.

Example#

summary = pr.summary()
print(summary.n_species)
print(summary.active_flow)
active_flow: Dict[str, int]#
goal_atleast: Dict[str, int]#
goal_exact: Dict[str, int]#
initial_marking: Dict[str, int]#
n_reactions: int#
n_species: int#
synkit.CRN.Pathway.realizability.run_realizability_from_syncrn(crn: object, flow: Mapping[str, int] | None = None, *, initial_marking: Mapping[str, int] | None = None, species: str = 'label', reaction: str = 'id', verbose: bool = True) Tuple[PathwayRealizability, Dict[str, object]][source]#

Run König-style and exact BFS realizability tests on a SynCRN-like object.

This convenience wrapper:

  1. loads the SynCRN object and requested flow,

  2. builds the augmented Petri net,

  3. applies the sufficient König-style acyclicity test,

  4. runs exact bounded BFS realizability search,

  5. optionally prints a human-readable summary.

Parameters:
  • crn (object) – SynCRN-like object.

  • flow (Optional[Mapping[str, int]]) – Optional requested reaction firing counts.

  • initial_marking (Optional[Mapping[str, int]]) – Optional initial marking.

  • species (str) – Species tokenization mode.

  • reaction (str) – Reaction tokenization mode.

  • verbose (bool) – Whether to print a textual summary.

Returns:

Pair (pathway_realizability_instance, info_dict).

Return type:

Tuple[PathwayRealizability, Dict[str, object]]

Example#

pr, info = run_realizability_from_syncrn(
    syn,
    flow={"12": 1, "13": 1},
    initial_marking={"A": 2},
    verbose=True,
)
print(info["konig"])
print(info["bfs"])
print(info["certificate"])
synkit.CRN.Pathway.realizability.syncrn_to_pr_inputs(crn: object, flow: Mapping[str, int] | None = None, *, initial_marking: Mapping[str, int] | None = None, species: str = 'label', reaction: str = 'id') Tuple[List[str], Dict[str, Tuple[Dict[str, int], Dict[str, int]]], Dict[str, int], Dict[str, int]][source]#

Convert a SynCRN-like object into tokenized pathway-realizability inputs.

The returned tuple contains:

  • species tokens,

  • reaction-tokenized hyperedges,

  • resolved flow map keyed by reaction token,

  • resolved initial marking keyed by species token.

Parameters:
  • crn (object) – SynCRN-like object.

  • flow (Optional[Mapping[str, int]]) – Optional requested reaction firing counts.

  • initial_marking (Optional[Mapping[str, int]]) – Optional initial marking.

  • species (str) – Species tokenization mode.

  • reaction (str) – Reaction tokenization mode.

Returns:

Tuple (vertices, edges, flow_map, marking_map).

Return type:

Tuple[

List[str], Dict[str, Tuple[Dict[str, int], Dict[str, int]]], Dict[str, int], Dict[str, int],

]

Example#

vertices, edges, flow_map, marking_map = syncrn_to_pr_inputs(
    syn,
    flow={"12": 1},
    initial_marking={"A": 2},
    species="label",
    reaction="id",
)

Petri net#

class synkit.CRN.Petrinet.analyzer.PetriAnalyzer(crn: Any, *, rtol: float = 1e-12, max_siphon_size: int | None = None)[source]#

Bases: object

OOP wrapper for Petri-net style analysis on SynCRN-like inputs.

Accepted inputs are canonical SynCRN objects, SynCRN bipartite digraphs, and PetriNet objects.

The analyzer caches computed results so repeated access to already computed diagnostics does not trigger recomputation.

Parameters:
  • crn (Any) – SynCRN-like object or PetriNet.

  • rtol (float) – Relative tolerance used in numerical nullspace calculations.

  • max_siphon_size (Optional[int]) – Optional maximum siphon/trap size considered during enumeration.

Examples#

analyzer = PetriAnalyzer(crn, rtol=1e-12, max_siphon_size=4)
analyzer.compute_all()

print(analyzer.summary)
print(analyzer.as_dict())
print(analyzer.explain())
as_dict() Dict[str, Any][source]#

Convert the current analyzer state into a serializable dictionary.

Returns:

Dictionary containing cached analysis results and metadata.

Return type:

Dict[str, Any]

Examples#

analyzer = PetriAnalyzer(crn).compute_all()
payload = analyzer.as_dict()
print(payload["persistence_ok"])
check_persistence() PetriAnalyzer[source]#

Evaluate and cache the siphon-based persistence condition.

Both the boolean persistence condition and the detailed explanation structure are computed and stored.

Returns:

The analyzer itself, enabling method chaining.

Return type:

PetriAnalyzer

Examples#

analyzer = PetriAnalyzer(crn).check_persistence()
print(analyzer.persistence_ok)
print(analyzer.persistence_details)
compute_all() PetriAnalyzer[source]#

Compute all supported Petri-style diagnostics.

This is equivalent to calling compute_semiflows(), compute_siphons_traps(), and check_persistence() in sequence.

Returns:

The analyzer itself, enabling method chaining.

Return type:

PetriAnalyzer

Examples#

analyzer = PetriAnalyzer(crn).compute_all()
print(analyzer.summary)
compute_semiflows() PetriAnalyzer[source]#

Compute and cache P-semiflows and T-semiflows.

Returns:

The analyzer itself, enabling method chaining.

Return type:

PetriAnalyzer

Examples#

analyzer = PetriAnalyzer(crn).compute_semiflows()
print(analyzer.p_semiflows)
print(analyzer.t_semiflows)
compute_siphons_traps() PetriAnalyzer[source]#

Compute and cache siphons and traps.

Returns:

The analyzer itself, enabling method chaining.

Return type:

PetriAnalyzer

Examples#

analyzer = PetriAnalyzer(crn).compute_siphons_traps()
print(analyzer.siphons)
print(analyzer.traps)
explain() str[source]#

Return a compact human-readable explanation of current results.

Returns:

Summary string describing persistence and the number of computed objects, or a message indicating that no computation has been run.

Return type:

str

Examples#

analyzer = PetriAnalyzer(crn).compute_all()
print(analyzer.explain())
property p_semiflows: ndarray | None#

Return cached P-semiflows.

Returns:

Cached P-semiflow basis, or None if not yet computed.

Return type:

Optional[numpy.ndarray]

property persistence_details: PersistenceCheckResult | None#

Return cached detailed persistence analysis.

Returns:

Cached persistence detail object, or None if not yet computed.

Return type:

Optional[PersistenceCheckResult]

property persistence_ok: bool | None#

Return cached persistence status.

Returns:

Cached persistence status, or None if not yet computed.

Return type:

Optional[bool]

property petri: PetriNet#

Return the internal Petri-net representation.

Returns:

Internal Petri-net view used for structural analysis.

Return type:

PetriNet

property siphons: List[Set[str]] | None#

Return cached siphons.

Returns:

Cached siphons, or None if not yet computed.

Return type:

Optional[List[Set[str]]]

property summary: PetriSummary | None#

Return a structured summary if all diagnostics are available.

Returns:

A PetriSummary if all components are computed, otherwise None.

Return type:

Optional[PetriSummary]

property t_semiflows: ndarray | None#

Return cached T-semiflows.

Returns:

Cached T-semiflow basis, or None if not yet computed.

Return type:

Optional[numpy.ndarray]

property traps: List[Set[str]] | None#

Return cached traps.

Returns:

Cached traps, or None if not yet computed.

Return type:

Optional[List[Set[str]]]

class synkit.CRN.Petrinet.analyzer.PetriSummary(p_semiflows: ndarray, t_semiflows: ndarray, siphons: List[Set[str]], traps: List[Set[str]], persistence_ok: bool, place_order: List[str], transition_order: List[str])[source]#

Bases: object

Structured container summarizing Petri-style SynCRN diagnostics.

Parameters:
  • p_semiflows (numpy.ndarray) – Numerical basis of P-semiflows, arranged as columns.

  • t_semiflows (numpy.ndarray) – Numerical basis of T-semiflows, arranged as columns.

  • siphons (List[Set[str]]) – Detected siphons as sets of place labels.

  • traps (List[Set[str]]) – Detected traps as sets of place labels.

  • persistence_ok (bool) – Whether the tested siphon-based persistence condition is satisfied.

  • place_order (List[str]) – Place ordering associated with the Petri/stoichiometric representation.

  • transition_order (List[str]) – Transition ordering associated with the Petri/stoichiometric representation.

p_semiflows: ndarray#
persistence_ok: bool#
place_order: List[str]#
siphons: List[Set[str]]#
t_semiflows: ndarray#
transition_order: List[str]#
traps: List[Set[str]]#
class synkit.CRN.Petrinet.net.PetriNet[source]#

Bases: object

Minimal Petri net container with marking semantics and SynCRN metadata.

Places correspond to species and transitions correspond to reactions. The class stores a lightweight Petri-net representation with utilities for adding places and transitions, checking enabledness, firing transitions, and converting between mapping-based and tuple-based markings.

Attributes#

places:

Set of place identifiers.

transitions:

Mapping from transition id to Transition.

place_labels:

Optional human-readable labels for places.

transition_labels:

Optional human-readable labels for transitions.

place_source_node_ids:

Provenance mapping for places.

transition_source_node_ids:

Provenance mapping for transitions.

graph_attrs:

Graph-level metadata copied from the source.

metadata:

Additional metadata.

Example#

net = PetriNet()
net.add_place("A")
net.add_place("B")
net.add_transition("r1", pre={"A": 1}, post={"B": 1})

m0 = {"A": 1}
assert net.enabled(m0, "r1")
m1 = net.fire(m0, "r1")
print(m1)   # {'A': 0, 'B': 1}
add_place(p: str, *, label: str | None = None, source_node_id: Hashable | None = None) None[source]#

Add a place to the Petri net.

If the place already exists, only optional metadata is updated.

Parameters:
  • p (Place) – Place identifier.

  • label (Optional[str]) – Optional display label.

  • source_node_id (Optional[Hashable]) – Optional provenance node id from the source CRN.

Returns:

None

Return type:

None

add_transition(tid: str, pre: Mapping[str, int], post: Mapping[str, int], *, label: str | None = None, source_reaction_id: str | None = None, metadata: MutableMapping[str, Any] | None = None) None[source]#

Add or replace a transition in the Petri net.

Zero or invalid non-positive weights are filtered out before storage. Any places referenced by pre or post are created automatically.

Parameters:
  • tid (TransitionId) – Transition identifier.

  • pre (Mapping[Place, int]) – Input arc multiset mapping place -> coefficient.

  • post (Mapping[Place, int]) – Output arc multiset mapping place -> coefficient.

  • label (Optional[str]) – Optional display label.

  • source_reaction_id (Optional[str]) – Optional source reaction identifier.

  • metadata (Optional[MutableMapping[str, Any]]) – Optional metadata attached to the transition.

Returns:

None

Return type:

None

Example#

net.add_transition(
    "r1",
    pre={"A": 2, "B": 1},
    post={"C": 1},
    label="2A + B -> C",
)
enabled(marking: Mapping[str, int], tid: str) bool[source]#

Test whether a transition is enabled under a marking.

A transition is enabled if every required input place has at least the corresponding token count.

Parameters:
  • marking (Marking) – Current marking as place -> token_count.

  • tid (TransitionId) – Transition identifier.

Returns:

True if the transition is enabled, else False.

Return type:

bool

fire(marking: Mapping[str, int], tid: str) Dict[str, int][source]#

Fire a transition and return the successor marking.

This function does not itself check enabledness. If the transition is not enabled, negative token counts may appear in the result.

Parameters:
  • marking (Marking) – Current marking.

  • tid (TransitionId) – Transition identifier to fire.

Returns:

Successor marking after consuming pre and producing post.

Return type:

Dict[Place, int]

Example#

m0 = {"A": 2, "B": 1}
m1 = net.fire(m0, "r1")
classmethod from_syncrn(crn: Any) PetriNet[source]#

Build a Petri-net view directly from SynCRN incidence data.

Parameters:

crn (Any) – SynCRN-like object or SynCRN bipartite digraph.

Returns:

Petri net constructed from the canonical incidence view.

Return type:

PetriNet

Example#

net = PetriNet.from_syncrn(crn)
print(net.place_order)
print(net.transition_order)
marking_to_tuple(m: Mapping[str, int]) Tuple[int, ...][source]#

Convert a mapping-based marking into a tuple in place order.

Parameters:

m (Marking) – Marking mapping.

Returns:

Tuple of token counts aligned to place_order.

Return type:

Tuple[int, …]

place_name(p: str) str[source]#

Return the display label of a place if available.

Parameters:

p (Place) – Place identifier.

Returns:

Display label or the identifier itself.

Return type:

str

property place_order: List[str]#

Return places in insertion order.

Returns:

Ordered place identifiers.

Return type:

List[Place]

to_pre_post() Dict[str, Any][source]#

Export the Petri net as place-indexed pre/post adjacency maps.

The returned structure is often convenient for reachability, firing, or incidence-based downstream algorithms.

Returns:

Dictionary containing places, transitions, labels, pre/post maps, graph attributes, and metadata.

Return type:

Dict[str, Any]

Example#

data = net.to_pre_post()
print(data["pre"])
print(data["post"])
transition_name(tid: str) str[source]#

Return the display label of a transition if available.

Parameters:

tid (TransitionId) – Transition identifier.

Returns:

Display label or the identifier itself.

Return type:

str

property transition_order: List[str]#

Return transitions in insertion order.

Returns:

Ordered transition identifiers.

Return type:

List[TransitionId]

tuple_to_marking(values: Iterable[int]) Dict[str, int][source]#

Convert a tuple-like token vector into a sparse marking mapping.

Zero entries are omitted from the returned dictionary.

Parameters:

values (Iterable[int]) – Iterable of token counts aligned to place_order.

Returns:

Sparse marking mapping.

Return type:

Dict[Place, int]

class synkit.CRN.Petrinet.net.SynCRNIncidence(species_order: ~typing.List[str], reaction_order: ~typing.List[str], species_labels: ~typing.Dict[str, str], reaction_labels: ~typing.Dict[str, str], pre: ~typing.Dict[str, ~typing.Dict[str, int]], post: ~typing.Dict[str, ~typing.Dict[str, int]], species_source_node_ids: ~typing.Dict[str, ~typing.Hashable] = <factory>, reaction_source_node_ids: ~typing.Dict[str, ~typing.Hashable] = <factory>, graph_attrs: ~typing.Dict[str, ~typing.Any] = <factory>, metadata: ~typing.Dict[str, ~typing.Any] = <factory>)[source]#

Bases: object

Canonical species–reaction incidence view extracted from a SynCRN-like object.

This dataclass stores a normalized incidence representation that can be constructed either from a SynCRN-style object exposing species and reactions mappings, or from a bipartite networkx.DiGraph returned by SynCRN.to_digraph().

The canonical representation separates:

  • species order

  • reaction order

  • species and reaction labels

  • pre-incidence stoichiometry

  • post-incidence stoichiometry

  • source-node provenance metadata

Parameters:
  • species_order (List[str]) – Ordered list of canonical species identifiers.

  • reaction_order (List[str]) – Ordered list of canonical reaction identifiers.

  • species_labels (Dict[str, str]) – Mapping from species identifier to display label.

  • reaction_labels (Dict[str, str]) – Mapping from reaction identifier to display label.

  • pre (Dict[str, Dict[str, int]]) – Mapping reaction_id -> {species_id: stoichiometric_coefficient} for reactants / input arcs.

  • post (Dict[str, Dict[str, int]]) – Mapping reaction_id -> {species_id: stoichiometric_coefficient} for products / output arcs.

  • species_source_node_ids (Dict[str, Hashable]) – Mapping from canonical species identifier to original source node id.

  • reaction_source_node_ids (Dict[str, Hashable]) – Mapping from canonical reaction identifier to original source node id.

  • graph_attrs (Dict[str, Any]) – Graph-level metadata copied from the source object or source graph.

  • metadata (Dict[str, Any]) – Additional extraction metadata.

Example#

incidence = SynCRNIncidence(
    species_order=["A", "B", "C"],
    reaction_order=["r1"],
    species_labels={"A": "A", "B": "B", "C": "C"},
    reaction_labels={"r1": "A + B -> C"},
    pre={"r1": {"A": 1, "B": 1}},
    post={"r1": {"C": 1}},
)
graph_attrs: Dict[str, Any]#
metadata: Dict[str, Any]#
post: Dict[str, Dict[str, int]]#
pre: Dict[str, Dict[str, int]]#
reaction_labels: Dict[str, str]#
reaction_order: List[str]#
reaction_source_node_ids: Dict[str, Hashable]#
species_labels: Dict[str, str]#
species_order: List[str]#
species_source_node_ids: Dict[str, Hashable]#
class synkit.CRN.Petrinet.net.Transition(tid: str, pre: ~typing.Dict[str, int], post: ~typing.Dict[str, int], label: str | None = None, source_reaction_id: str | None = None, metadata: ~typing.Dict[str, ~typing.Any] = <factory>)[source]#

Bases: object

Petri-net transition with stoichiometric input/output multisets.

A transition corresponds to one reaction node in the source SynCRN-like representation.

Parameters:
  • tid (TransitionId) – Canonical transition identifier.

  • pre (Dict[Place, int]) – Input multiset mapping place -> coefficient.

  • post (Dict[Place, int]) – Output multiset mapping place -> coefficient.

  • label (Optional[str]) – Optional display label.

  • source_reaction_id (Optional[str]) – Optional source reaction identifier from the original CRN object.

  • metadata (Dict[str, Any]) – Optional transition metadata dictionary.

Example#

t = Transition(
    tid="r1",
    pre={"A": 1, "B": 2},
    post={"C": 1},
    label="A + 2B -> C",
)
label: str | None = None#
metadata: Dict[str, Any]#
post: Dict[str, int]#
pre: Dict[str, int]#
source_reaction_id: str | None = None#
tid: str#
synkit.CRN.Petrinet.net.extract_syncrn_incidence(crn: Any) SynCRNIncidence[source]#

Extract a canonical incidence view from a SynCRN-like object or digraph.

The function accepts three input styles:

  • a networkx.DiGraph in SynCRN bipartite format

  • a SynCRN-like object exposing species and reactions

  • an object exposing to_digraph() that returns such a graph

Parameters:

crn (Any) – SynCRN-like object or bipartite digraph.

Returns:

Canonical incidence representation.

Return type:

SynCRNIncidence

Raises:

TypeError – If the input cannot be interpreted as a supported SynCRN source.

Example#

incidence = extract_syncrn_incidence(crn)
print(incidence.pre)
print(incidence.post)
class synkit.CRN.Petrinet.persistence.PersistenceCheckResult(persistence_ok: bool, siphons: List[Set[str]], semiflow_supports: List[Set[str]], uncovered_siphons: List[Set[str]])[source]#

Bases: object

Structured result of the siphon-based persistence sufficient test.

persistence_ok: bool#
semiflow_supports: List[Set[str]]#
siphons: List[Set[str]]#
uncovered_siphons: List[Set[str]]#
synkit.CRN.Petrinet.persistence.siphon_persistence_condition(crn: Any, *, rtol: float = 1e-12, max_siphon_size: int | None = None) bool[source]#

Check the Angeli–De Leenheer–Sontag siphon/P-semiflow sufficient condition.

The condition holds when every minimal siphon contains the support of some P-semiflow.

synkit.CRN.Petrinet.persistence.siphon_persistence_details(crn: Any, *, rtol: float = 1e-12, max_siphon_size: int | None = None, support_tol: float = 1e-08) PersistenceCheckResult[source]#

Return detailed information for the siphon-based persistence test.

synkit.CRN.Petrinet.semiflows.find_p_semiflows(crn: Any, *, rtol: float = 1e-12) ndarray[source]#

Compute P-semiflows, also called place invariants.

P-semiflows form a basis of the left kernel of the stoichiometric matrix, that is ker(S^T). The returned matrix has shape (n_species, k), where each column is one basis vector.

For SynCRN-like graph inputs, the computation delegates to synkit.CRN.Props.stoich.left_nullspace(). For native PetriNet inputs, the stoichiometric matrix is built locally and the null space is computed numerically.

Parameters:
  • crn (Any) – Petri net, SynCRN-like object, or supported bipartite graph.

  • rtol (float) – Relative tolerance used for null-space detection.

Returns:

Matrix whose columns form a basis of the P-semiflow space.

Return type:

np.ndarray

Example#

from synkit.CRN.Structure import SynCRN
from synkit.CRN.Petrinet.semiflows import find_p_semiflows

syn = SynCRN.from_reaction_strings(["A>>B", "B>>A"])
basis = find_p_semiflows(syn)
print(basis.shape)
synkit.CRN.Petrinet.semiflows.find_t_semiflows(crn: Any, *, rtol: float = 1e-12) ndarray[source]#

Compute T-semiflows, also called transition invariants.

T-semiflows form a basis of the right kernel of the stoichiometric matrix, that is ker(S). The returned matrix has shape (n_reactions, k), where each column is one basis vector.

For SynCRN-like graph inputs, the computation delegates to synkit.CRN.Props.stoich.right_nullspace(). For native PetriNet inputs, the stoichiometric matrix is built locally and the null space is computed numerically.

Parameters:
  • crn (Any) – Petri net, SynCRN-like object, or supported bipartite graph.

  • rtol (float) – Relative tolerance used for null-space detection.

Returns:

Matrix whose columns form a basis of the T-semiflow space.

Return type:

np.ndarray

Example#

from synkit.CRN.Structure import SynCRN
from synkit.CRN.Petrinet.semiflows import find_t_semiflows

syn = SynCRN.from_reaction_strings(["A>>B", "B>>A"])
basis = find_t_semiflows(syn)
print(basis.shape)
synkit.CRN.Petrinet.semiflows.semiflow_supports(crn: Any, *, kind: str = 'p', rtol: float = 1e-12, support_tol: float = 1e-08) List[Dict[str, float]][source]#

Return sparsified P-semiflow or T-semiflow supports.

The result is a list of sparse dictionaries, one per basis column. For P-semiflows, keys are species or place identifiers. For T-semiflows, keys are reaction or transition identifiers.

Parameters:
  • crn (Any) – Petri net, SynCRN-like object, or supported bipartite graph.

  • kind (str) – Either "p" for P-semiflows or "t" for T-semiflows.

  • rtol (float) – Relative tolerance used for null-space detection.

  • support_tol (float) – Threshold below which basis coefficients are treated as zero when constructing sparse supports.

Returns:

List of sparse support dictionaries.

Return type:

List[Dict[str, float]]

Raises:

ValueError – If kind is not "p" or "t".

Example#

from synkit.CRN.Structure import SynCRN
from synkit.CRN.Petrinet.semiflows import semiflow_supports

syn = SynCRN.from_reaction_strings(["A>>B", "B>>A"])

p_supports = semiflow_supports(syn, kind="p")
t_supports = semiflow_supports(syn, kind="t")

print(p_supports)
print(t_supports)
synkit.CRN.Petrinet.semiflows.stoichiometric_matrix(crn: Any) Tuple[List[str], List[str], ndarray][source]#

Return row order, column order, and stoichiometric matrix for a network.

This is a thin wrapper around synkit.CRN.Props.stoich for SynCRN-like graph inputs, augmented with explicit row and column orders so semiflow supports can be interpreted. For native PetriNet inputs, the matrix is assembled directly from the transition multisets.

Supported inputs include:

  • a PetriNet

  • a SynCRN-like object accepted by synkit.CRN.Props.helper._as_graph()

  • a NetworkX bipartite graph in SynCRN species-rule format

Parameters:

crn (Any) – Petri net, SynCRN-like object, or supported bipartite graph.

Returns:

Tuple (species_order, reaction_order, S), where species_order defines the row labels of S and reaction_order defines the column labels.

Return type:

Tuple[List[str], List[str], np.ndarray]

Example#

from synkit.CRN.Structure import SynCRN
from synkit.CRN.Petrinet.semiflows import stoichiometric_matrix

syn = SynCRN.from_reaction_strings(["A>>B", "B>>A"])
species_order, reaction_order, S = stoichiometric_matrix(syn)

print(species_order)
print(reaction_order)
print(S.shape)
synkit.CRN.Petrinet.structure.find_siphons(crn: Any, *, max_size: int | None = None, names: str = 'label') List[Set[str]][source]#

Enumerate inclusion-minimal siphons of a SynCRN Petri-net view.

The search is performed by brute-force subset enumeration up to the requested size bound, followed by inclusion-minimal filtering.

Parameters:
  • crn (Any) – SynCRN-like object or PetriNet.

  • max_size (int | None) – Maximum siphon size to consider. None means all sizes.

  • names (str) – Whether to return internal place ids or species labels. Supported values are "id" and "label".

Returns:

Inclusion-minimal siphons.

Return type:

List[Set[str]]

synkit.CRN.Petrinet.structure.find_traps(crn: Any, *, max_size: int | None = None, names: str = 'label') List[Set[str]][source]#

Enumerate inclusion-minimal traps of a SynCRN Petri-net view.

The search is performed by brute-force subset enumeration up to the requested size bound, followed by inclusion-minimal filtering.

Parameters:
  • crn (Any) – SynCRN-like object or PetriNet.

  • max_size (int | None) – Maximum trap size to consider. None means all sizes.

  • names (str) – Whether to return internal place ids or species labels. Supported values are "id" and "label".

Returns:

Inclusion-minimal traps.

Return type:

List[Set[str]]

synkit.CRN.Petrinet.structure.species_transition_neighborhoods(crn: Any) Dict[str, Dict[str, List[str]]][source]#

Return per-species producer and consumer transition neighborhoods.

This is a small structural helper that is often useful when debugging siphons, traps, and reachability issues.

The returned dictionary is keyed by internal place id. For each place, the value contains the display label, the transitions that produce tokens into the place, and the transitions that consume tokens from it.

Parameters:

crn (Any) – SynCRN-like object or PetriNet.

Returns:

Mapping from place id to a dictionary with keys "label", "producer_transitions", and "consumer_transitions".

Return type:

Dict[str, Dict[str, List[str]]]

Properties#

class synkit.CRN.Props.dynamics.StructuralSingularitySummary(n_species: int, structural_rank: int, has_perfect_matching: bool, pattern_singular: bool, determinant_checked: bool, determinant_expr: Any | None = None, determinant_is_zero: bool | None = None)[source]#

Bases: object

Summary of structural singularity diagnostics for a symbolic Jacobian.

The diagnostics are species-level because the Jacobian is a species-by-species object, even though the underlying SynCRN graph is bipartite with species nodes and rule nodes.

Parameters:
  • n_species (int) – Number of species, i.e. Jacobian dimension.

  • structural_rank (int) – Structural rank inferred from the Jacobian sparsity pattern.

  • has_perfect_matching (bool) – Whether the bipartite sparsity graph admits a perfect matching.

  • pattern_singular (bool) – Whether the Jacobian is singular at the structural-pattern level.

  • determinant_checked (bool) – Whether an exact symbolic determinant was computed.

  • determinant_expr (Optional[Any]) – Exact symbolic determinant expression, if evaluated.

  • determinant_is_zero (Optional[bool]) – Whether the exact symbolic determinant simplified to zero.

Example#

summary = StructuralSingularitySummary(
    n_species=3,
    structural_rank=2,
    has_perfect_matching=False,
    pattern_singular=True,
    determinant_checked=False,
)

print(summary.classification)
print(summary.to_dict())
property classification: str#

Return a concise structural-singularity classification label.

Possible values include pattern-level singularity, exact symbolic singularity, exact symbolic nonsingularity, or the case where only the sparsity-pattern analysis was performed.

Returns:

Classification string summarizing the diagnostic outcome.

Return type:

str

Example#

summary = StructuralSingularitySummary(
    n_species=4,
    structural_rank=4,
    has_perfect_matching=True,
    pattern_singular=False,
    determinant_checked=True,
    determinant_is_zero=False,
)

print(summary.classification)
determinant_checked: bool#
determinant_expr: Any | None = None#
determinant_is_zero: bool | None = None#
has_perfect_matching: bool#
n_species: int#
pattern_singular: bool#
structural_rank: int#
to_dict() Dict[str, Any][source]#

Convert the summary to a plain dictionary.

Symbolic determinant expressions are stringified so the result is easier to serialize or log.

Returns:

Plain dictionary representation of the summary.

Return type:

Dict[str, Any]

Example#

d = summary.to_dict()
print(d["classification"])
synkit.CRN.Props.dynamics.jacobian_sign_pattern(crn: Any, *, tol: float = 1e-12) Tuple[List[Any], ndarray][source]#

Compute the structural sign pattern of the symbolic Jacobian.

Returned entries are one of:

  • "0"

  • "+"

  • "-"

  • "mixed"

The value "mixed" means that multiple structurally valid paths exist with conflicting positive and negative net effects.

Parameters:
  • crn (Any) – SynCRN graph or SynCRN-like object in the species/rule representation.

  • tol (float) – Tolerance used for structural zero testing.

Returns:

Tuple containing:

  • species node order,

  • Jacobian sign-pattern matrix.

Return type:

Tuple[List[Any], numpy.ndarray]

Example#

species_order, P = jacobian_sign_pattern(crn)
print(species_order)
print(P)
synkit.CRN.Props.dynamics.jacobian_sparsity(crn: Any, *, tol: float = 1e-12) Tuple[List[Any], ndarray][source]#

Return the boolean sparsity pattern of the symbolic Jacobian.

Entry A[i, k] is True if species k can structurally influence species i through at least one rule under the local linearized dynamics.

Parameters:
  • crn (Any) – SynCRN graph or SynCRN-like object in the species/rule representation.

  • tol (float) – Tolerance used for structural zero testing.

Returns:

Tuple containing:

  • species node order,

  • boolean Jacobian sparsity matrix.

Return type:

Tuple[List[Any], numpy.ndarray]

Example#

species_order, A = jacobian_sparsity(crn)
print(species_order)
print(A.astype(int))
synkit.CRN.Props.dynamics.species_influence_graph(crn: Any, *, tol: float = 1e-12, use_labels: bool = False) DiGraph[source]#

Build the species influence graph induced by the symbolic Jacobian.

Nodes represent species. A directed edge u -> v is added when species u can structurally influence species v in the local linearized dynamics.

Edge attribute sign is one of:

  • "+"

  • "-"

  • "mixed"

Additional edge attributes record the original source and target species node identifiers.

Parameters:
  • crn (Any) – SynCRN graph or SynCRN-like object in the species/rule representation.

  • tol (float) – Tolerance used for structural zero testing.

  • use_labels (bool) – If True and crn is a NetworkX graph, use node labels when available; otherwise use original node identifiers.

Returns:

Directed species influence graph.

Return type:

nx.DiGraph

Example#

G_inf = species_influence_graph(crn, use_labels=True)

print(G_inf.nodes(data=True))
print(G_inf.edges(data=True))
synkit.CRN.Props.dynamics.structural_singularity_summary(crn: Any, *, tol: float = 1e-12, max_exact_size: int = 7, symbol_prefix: str = 'rprime') StructuralSingularitySummary[source]#

Diagnose structural singularity of the symbolic Jacobian.

This routine performs two levels of analysis:

  1. structural-rank and perfect-matching diagnostics on the Jacobian sparsity pattern, and

  2. optional exact symbolic determinant evaluation for sufficiently small systems.

Pattern-level singularity indicates that the Jacobian is singular for all admissible parameter values consistent with the sparsity structure. If the pattern is not singular, an exact determinant test may still detect symbolic cancellation and prove singularity for small systems.

Parameters:
  • crn (Any) – SynCRN graph or SynCRN-like object in the species/rule representation.

  • tol (float) – Tolerance used for structural zero testing.

  • max_exact_size (int) – Maximum number of species for which the exact symbolic determinant is computed.

  • symbol_prefix (str) – Prefix used for symbolic reactivity variables.

Returns:

Structured summary of Jacobian structural-singularity diagnostics.

Return type:

StructuralSingularitySummary

Raises:

ImportError – If exact symbolic determinant evaluation is requested but sympy is not available.

Example#

summary = structural_singularity_summary(
    crn,
    max_exact_size=6,
    symbol_prefix="rprime",
)

print(summary)
print(summary.to_dict())
print(summary.classification)
synkit.CRN.Props.dynamics.symbolic_jacobian(crn: Any, *, symbol_prefix: str = 'rprime', tol: float = 1e-12) Tuple[List[Any], List[Any], 'sp.Matrix'][source]#

Build the symbolic Jacobian G = S R.

Here S is the species-by-rule stoichiometric matrix and R is the rule-by-species symbolic reactivity matrix induced by reactant incidence. The resulting Jacobian is a species-by-species symbolic matrix describing local structural influence in the CRN dynamics.

Parameters:
  • crn (Any) – SynCRN graph or SynCRN-like object in the species/rule representation.

  • symbol_prefix (str) – Prefix used for symbolic reactivity variables.

  • tol (float) – Tolerance forwarded to symbolic_reactivity_matrix().

Returns:

Tuple containing:

  • species node order,

  • rule node order,

  • symbolic Jacobian G.

Return type:

Tuple[List[Any], List[Any], sp.Matrix]

Raises:

ImportError – If sympy is not available.

Example#

species_order, rule_order, G = symbolic_jacobian(crn)
print(G.shape)
print(G)
synkit.CRN.Props.dynamics.symbolic_reactivity_matrix(crn: Any, *, symbol_prefix: str = 'rprime', tol: float = 1e-12) Tuple[List[Any], List[Any], 'sp.Matrix'][source]#

Build the symbolic reactivity matrix R.

For a SynCRN with n_species species nodes and n_rules rule nodes, the matrix R has shape (n_rules, n_species). Entry R[j, i] is a positive symbolic variable if species i is a reactant of rule j, and zero otherwise.

This matrix captures the structural dependence of reaction rates on species concentrations without assuming a specific kinetic law beyond positive reactant sensitivity.

Parameters:
  • crn (Any) – SynCRN graph or SynCRN-like object in the species/rule representation.

  • symbol_prefix (str) – Prefix used when naming symbolic reactivity variables.

  • tol (float) – Tolerance used to decide whether a reactant stoichiometric entry is structurally positive.

Returns:

Tuple containing:

  • species node order,

  • rule node order,

  • symbolic reactivity matrix R.

Return type:

Tuple[List[Any], List[Any], sp.Matrix]

Raises:

ImportError – If sympy is not available.

Example#

species_order, rule_order, R = symbolic_reactivity_matrix(crn)
print(species_order)
print(rule_order)
print(R)
class synkit.CRN.Props.stoich.StoichSummary(n_species: int, n_reactions: int, rank: int)[source]#

Bases: object

Lightweight stoichiometric summary of a SynCRN.

The field name n_reactions is retained for backward compatibility even though the current SynCRN representation uses rule nodes as process columns.

Parameters:
  • n_species (int) – Number of species rows in the stoichiometric matrix.

  • n_reactions (int) – Number of process columns in the stoichiometric matrix. In the current representation this corresponds to the number of rule nodes.

  • rank (int) – Numerical rank of the stoichiometric matrix.

dim_left_kernel: int#
dim_right_kernel: int#
classmethod from_crn(crn: Any) StoichSummary[source]#

Construct a summary directly from a CRN object or graph.

Parameters:

crn (Any) – A NetworkX bipartite graph or a SynCRN-like object containing one.

Returns:

Stoichiometric summary derived from the CRN.

Return type:

StoichSummary

property is_full_rank: bool#

Whether the stoichiometric matrix has full rank.

Returns:

True when rank == min(n_species, n_reactions), otherwise False.

Return type:

bool

property is_underdetermined: bool#

Whether the right kernel is non-trivial.

Equivalently, this checks whether rank < n_reactions.

Returns:

True if dim_right_kernel > 0, else False.

Return type:

bool

n_reactions: int#
n_species: int#
rank: int#
to_dict() Dict[str, Any][source]#

Convert the summary into a plain dictionary.

Returns:

Dictionary representation of the summary.

Return type:

Dict[str, Any]

synkit.CRN.Props.stoich.build_S(crn: Any) Tuple[List[Any], List[Any], ndarray][source]#

Build the stoichiometric matrix S = S^+ - S^-.

Parameters:

crn (Any) – A NetworkX bipartite graph or a SynCRN-like object containing one.

Returns:

A 3-tuple (species_order, rule_order, S) where S is the species x rule stoichiometric matrix.

Return type:

Tuple[List[Any], List[Any], np.ndarray]

synkit.CRN.Props.stoich.build_S_minus_plus(crn: Any) Tuple[List[Any], List[Any], ndarray, ndarray][source]#

Build the reactant matrix S^- and product matrix S^+ from a SynCRN.

The input is interpreted as a bipartite species-rule incidence graph. Rows correspond to species nodes and columns correspond to rule nodes.

Graph conventions#

Nodes:
  • species nodes have kind="species"

  • rule nodes have kind="rule"

Edges:
  • role: "reactant" or "product"

  • stoich: stoichiometric coefficient, default 1.0

Orientation#

The graph may be directed or undirected. The edge role attribute is treated as the source of truth, and endpoint order is not assumed to encode reactant/product direction.

param crn:

A NetworkX bipartite graph or a SynCRN-like object containing one.

type crn:

Any

returns:

A 4-tuple (species_order, rule_order, S_minus, S_plus) where species_order defines row order, rule_order defines column order, S_minus contains reactant stoichiometries, and S_plus contains product stoichiometries.

rtype:

Tuple[List[Any], List[Any], np.ndarray, np.ndarray]

synkit.CRN.Props.stoich.integer_conservation_laws(crn: Any, *, rtol: float = 1e-12) List[List[int]][source]#

Return an approximate minimal integer basis for ker(S^T).

Each returned vector corresponds to an approximate conservation law over species, obtained by converting floating null-space basis vectors into reduced integer vectors.

Parameters:
  • crn (Any) – A NetworkX bipartite graph or a SynCRN-like object containing one.

  • rtol (float) – Relative tolerance used in null-space computation.

Returns:

List of integer vectors approximating a basis of the left kernel.

Return type:

List[List[int]]

synkit.CRN.Props.stoich.left_nullspace(crn: Any, *, rtol: float = 1e-12) ndarray[source]#

Compute a basis for the left null space ker(S^T).

In CRN language, these directions correspond to conservation-law vectors over species.

Parameters:
  • crn (Any) – A NetworkX bipartite graph or a SynCRN-like object containing one.

  • rtol (float) – Relative tolerance used in null-space computation.

Returns:

Matrix whose columns form a basis of ker(S^T).

Return type:

np.ndarray

synkit.CRN.Props.stoich.left_right_kernels(crn: Any, *, rtol: float = 1e-12) Tuple[ndarray, ndarray][source]#

Compute both left and right kernels of the stoichiometric matrix.

Parameters:
  • crn (Any) – A NetworkX bipartite graph or a SynCRN-like object containing one.

  • rtol (float) – Relative tolerance used in null-space computation.

Returns:

Pair (left_basis, right_basis) where left_basis spans ker(S^T) and right_basis spans ker(S).

Return type:

Tuple[np.ndarray, np.ndarray]

synkit.CRN.Props.stoich.right_nullspace(crn: Any, *, rtol: float = 1e-12) ndarray[source]#

Compute a basis for the right null space ker(S).

In CRN or Petri-net language, these directions correspond to rule-flux modes or T-semiflows.

Parameters:
  • crn (Any) – A NetworkX bipartite graph or a SynCRN-like object containing one.

  • rtol (float) – Relative tolerance used in null-space computation.

Returns:

Matrix whose columns form a basis of ker(S).

Return type:

np.ndarray

synkit.CRN.Props.stoich.stoichiometric_matrix(crn: Any) ndarray[source]#

Return the species x rule stoichiometric matrix S.

Parameters:

crn (Any) – A NetworkX bipartite graph or a SynCRN-like object containing one.

Returns:

Stoichiometric matrix with species as rows and rule nodes as columns.

Return type:

np.ndarray

synkit.CRN.Props.stoich.stoichiometric_rank(crn: Any, *, tol: float = 1e-10) int[source]#

Compute the numerical rank of the stoichiometric matrix.

Parameters:
  • crn (Any) – A NetworkX bipartite graph or a SynCRN-like object containing one.

  • tol (float) – Numerical tolerance passed to numpy.linalg.matrix_rank.

Returns:

Rank of the stoichiometric matrix.

Return type:

int

synkit.CRN.Props.stoich.summary(crn: Any) StoichSummary[source]#

Compute a quick stoichiometric summary.

Parameters:

crn (Any) – A NetworkX bipartite graph or a SynCRN-like object containing one.

Returns:

Lightweight stoichiometric summary of the CRN.

Return type:

StoichSummary

class synkit.CRN.Props.thermo.ThermoSummary(conservative: bool | None, consistent: bool | None, example_conservation_law: ndarray | None, irreversible_futile_cycles: bool)[source]#

Bases: object

Lightweight container summarizing thermodynamic-like stoichiometric properties of a chemical reaction network.

This dataclass gathers the main outputs of the thermo module into a single object for convenient downstream inspection, reporting, or serialization. It is intentionally compact and stores only the most interpretable summary flags and one example conservation-law vector when available.

Parameters:
  • conservative (Optional[bool]) – Whether the network is conservative, i.e. whether there exists a strictly positive vector \(m > 0\) such that \(m^T S = 0\). The value may be None if the check is inconclusive.

  • consistent (Optional[bool]) – Whether the network is consistent, i.e. whether there exists a strictly positive vector \(v > 0\) such that \(S v = 0\). The value may be None if the check is inconclusive.

  • example_conservation_law (Optional[numpy.ndarray]) – Example normalized strictly positive left-kernel vector when one is found, otherwise None.

  • irreversible_futile_cycles (bool) – Boolean indicator of whether the right kernel \(\ker(S)\) is non-trivial. This is used here as a structural proxy for the presence of futile-cycle-like steady flux modes.

from synkit.CRN.Props.thermo import compute_thermo_summary

summary = compute_thermo_summary(hg)
print(summary.conservative)
print(summary.consistent)
print(summary.irreversible_futile_cycles)
print(summary.example_conservation_law)
conservative: bool | None#
consistent: bool | None#
example_conservation_law: ndarray | None#
irreversible_futile_cycles: bool#
synkit.CRN.Props.thermo.compute_conservativity(crn: Any, *, rtol: float = 1e-12, eps: float = 1e-08) tuple[bool | None, ndarray | None][source]#

Compute the conservativity status of a network together with an example positive conservation law when available.

This is the more informative counterpart of is_conservative(). It checks whether there exists a strictly positive vector \(m > 0\) such that \(m^T S = 0\), and if successful it also returns one normalized example vector.

Parameters:
  • crn (Any) – Hypergraph or bipartite NetworkX graph representing the chemical reaction network.

  • rtol (float) – Relative tolerance used in nullspace-based computations.

  • eps (float) – Absolute threshold used to test strict positivity of candidate conservation-law vectors.

Returns:

Tuple (flag, m) where flag is the conservativity result and m is an example normalized strictly positive conservation law if one was found, otherwise None.

Return type:

Tuple[Optional[bool], Optional[numpy.ndarray]]

from synkit.CRN.Props.thermo import compute_conservativity

flag, m = compute_conservativity(hg)
print("Conservative?", flag)
if m is not None:
    print("Example law:", m)
synkit.CRN.Props.thermo.compute_thermo_summary(crn: Any, *, rtol: float = 1e-12, eps: float = 1e-08) ThermoSummary[source]#

Compute a composite ThermoSummary describing key thermodynamic-like and structural stoichiometric properties of a chemical reaction network.

This helper combines the main thermo-related analyses into a single call:

  • conservativity: whether there exists a strictly positive vector

\(m > 0\) such that \(m^T S = 0\), - consistency: whether there exists a strictly positive flux vector \(v > 0\) such that \(S v = 0\), - irreversible futile-cycle proxy: whether the right kernel \(\ker(S)\) is non-trivial, - example conservation law: one normalized strictly positive left-kernel vector, when such a vector can be found.

The returned summary is intended as a lightweight diagnostic object for quick inspection of CRN thermodynamic structure without calling each helper individually.

Parameters:
  • crn (Any) – Hypergraph or bipartite NetworkX graph representing the chemical reaction network.

  • rtol (float) – Relative tolerance used in nullspace-based computations, especially when estimating kernel dimensions or checking whether the right kernel is non-trivial.

  • eps (float) – Absolute positivity threshold used when testing whether a candidate conservation law or flux mode is strictly positive.

Returns:

A ThermoSummary instance containing conservativity, consistency, an optional example positive conservation law, and a Boolean indicator for non-trivial steady-state flux cycles.

Return type:

ThermoSummary

from synkit.CRN.Props.thermo import compute_thermo_summary

summary = compute_thermo_summary(hg)

print("Conservative:", summary.conservative)
print("Consistent:", summary.consistent)
print("Has futile-cycle proxy:", summary.irreversible_futile_cycles)

if summary.example_conservation_law is not None:
    print("Example conservation law:", summary.example_conservation_law)

Note

The field irreversible_futile_cycles is used here as a structural proxy based on the existence of nonzero vectors in \(\ker(S)\). It should be interpreted as a stoichiometric indicator rather than as a full mechanistic proof of thermodynamic infeasibility.

synkit.CRN.Props.thermo.has_irreversible_futile_cycles(crn: Any, *, rtol: float = 1e-12) bool[source]#

Check whether the network admits non-trivial steady-state flux modes.

This function tests whether the right kernel \(\ker(S)\) is non-trivial, i.e. whether there exists a nonzero vector \(v\) such that

\[S v = 0.\]

A non-trivial right kernel indicates the presence of flux-mode-like directions that do not change net species amounts. In this module, this is used as a structural proxy for irreversible futile cycles, although it should be interpreted cautiously as a stoichiometric indicator rather than a full mechanistic proof.

Parameters:
  • crn (Any) – Hypergraph or bipartite NetworkX graph representing the chemical reaction network.

  • rtol (float) – Relative tolerance used in the nullspace computation.

Returns:

True if \(\ker(S)\) is non-trivial, otherwise False.

Return type:

bool

from synkit.CRN.Props.thermo import has_irreversible_futile_cycles

has_cycles = has_irreversible_futile_cycles(hg)
print("Has futile-cycle-like modes?", has_cycles)
synkit.CRN.Props.thermo.is_conservative(crn: Any, *, eps: float = 1e-08, rtol: float = 1e-12) bool | None[source]#

Check whether the chemical reaction network is conservative.

A network is called conservative here if there exists a strictly positive vector \(m > 0\) such that

\[m^T S = 0,\]

where \(S\) is the stoichiometric matrix. Such a vector can be interpreted as a positive conservation law over species.

This function returns only the Boolean-style status of the check. Use compute_conservativity() when an example conservation-law vector is also desired.

Parameters:
  • crn (Any) – Hypergraph or bipartite NetworkX graph representing the chemical reaction network.

  • eps (float) – Absolute threshold used to test strict positivity of candidate conservation-law vectors.

  • rtol (float) – Relative tolerance used in nullspace-based computations.

Returns:

  • True if a strictly positive conservation law exists,

  • False if no such law exists,

  • None if the result is inconclusive.

Return type:

Optional[bool]

from synkit.CRN.Props.thermo import is_conservative

flag = is_conservative(hg)
print("Conservative?", flag)
synkit.CRN.Props.thermo.is_consistent(crn: Any, *, eps: float = 1e-08) bool | None[source]#

Check whether the chemical reaction network is consistent.

Consistency is tested here by asking whether there exists a strictly positive flux vector \(v > 0\) such that

\[S v = 0,\]

where \(S\) is the stoichiometric matrix. In CRN terminology, this corresponds to the existence of a strictly positive right-kernel vector, or equivalently a positive T-semiflow.

If SciPy is available, the function attempts a linear-programming check. Otherwise it falls back to a nullspace-based heuristic.

Parameters:
  • crn (Any) – Hypergraph or bipartite NetworkX graph representing the chemical reaction network.

  • eps (float) – Absolute lower bound used to enforce strict positivity of candidate flux vectors.

Returns:

  • True if a strictly positive right-kernel vector exists,

  • False if no such vector exists,

  • None if the result is inconclusive.

Return type:

Optional[bool]

from synkit.CRN.Props.thermo import is_consistent

flag = is_consistent(hg)
print("Consistent?", flag)
synkit.CRN.Props.thermo.left_nullspace_from_matrix(S: ndarray, *, rtol: float = 1e-12) ndarray[source]#

Compute a basis for the left kernel \(\ker(S^T)\) directly from a stoichiometric matrix.

This helper is a matrix-level analogue of the graph-based nullspace functions in stoich. It is useful when the stoichiometric matrix is already available and one wants to avoid reconstructing it from the CRN representation.

If SciPy is available, the function uses scipy.linalg.null_space(). Otherwise it falls back to an SVD-based implementation using NumPy.

Parameters:
  • S (numpy.ndarray) – Stoichiometric matrix of shape (n_species, n_reactions).

  • rtol (float) – Relative tolerance used to determine the effective numerical rank in the nullspace computation.

Returns:

Matrix whose columns form a basis for \(\ker(S^T)\). The returned array has shape (n_species, k), where k is the dimension of the left kernel.

Return type:

numpy.ndarray

import numpy as np
from synkit.CRN.Props.thermo import left_nullspace_from_matrix

S = np.array([[-1.0], [1.0]])
L = left_nullspace_from_matrix(S)
print(L.shape)

Query#

class synkit.CRN.Query.kegg_api.KEGGClient(base_url: str = 'https://rest.kegg.jp', timeout: float = 60.0)[source]#

Bases: object

Lightweight REST client for the KEGG API.

This client provides a minimal wrapper around the KEGG REST interface and returns raw response text for a requested endpoint.

Parameters:
  • base_url (str) – Base KEGG REST endpoint.

  • timeout (float) – Request timeout in seconds.

Example#

client = KEGGClient(
    base_url="https://rest.kegg.jp",
    timeout=30.0,
)
text = client.get_text("get/hsa00010")
base_url: str#
get_optional_text(path: str) str | None[source]#

Send a GET request and return the response text when available.

Unlike get_text(), this method suppresses requests.HTTPError and returns None for HTTP-level failures such as 404 Not Found.

Parameters:

path (str) – Relative KEGG REST path.

Returns:

Response text if the request succeeds, otherwise None when an HTTP error occurs.

Return type:

Optional[str]

Raises:

requests.RequestException – Raised for non-HTTP request failures, such as connection errors or timeouts.

Example#

client = KEGGClient()
maybe_text = client.get_optional_text("get/hsa00010")
if maybe_text is not None:
    print(maybe_text[:200])
get_text(path: str) str[source]#

Send GET <base_url>/<path> and return the response body as text.

Parameters:

path (str) – Relative KEGG REST path, for example "get/hsa00010".

Returns:

Raw text returned by the KEGG REST API.

Return type:

str

Raises:
  • requests.HTTPError – Raised when the server responds with an HTTP error status.

  • requests.RequestException – Raised for transport-level request failures.

Example#

client = KEGGClient()
entry_text = client.get_text("get/hsa00010")
timeout: float#
class synkit.CRN.Query.kegg_extract.KEGGExtractor(client: KEGGClient | None = None, mapper_cls: type[Any] | None = None)[source]#

Bases: object

High-level extractor for KEGG pathway and module reaction data.

This class orchestrates KEGG entry retrieval, module membership parsing, reaction equation collection, compound-table construction, reaction SMILES assembly, and optional atom mapping.

Parameters:
  • client (Optional[KEGGClient]) – Optional KEGG REST client. When omitted, a default KEGGClient instance is created during __post_init__().

  • mapper_cls (Optional[type[Any]]) – Optional atom-mapper class used by atom_map_reactions(). The class must be instantiable without arguments and must provide get_attention_guided_atom_maps.

Example#

extractor = KEGGExtractor()
data = extractor.build_module_json(
    "M00001",
    with_compounds=True,
    with_atom_maps=False,
)
atom_map_reactions(reaction_smiles_by_id: Mapping[str, str]) dict[str, str | None][source]#

Atom-map reaction SMILES using RXNMapper.

Parameters:

reaction_smiles_by_id (Mapping[str, str]) – Mapping {reaction_id: reaction_smiles}.

Returns:

Mapping {reaction_id: mapped_reaction_smiles_or_none}.

Return type:

dict[str, Optional[str]]

Example#

mapped = extractor.atom_map_reactions({"R00001": "CCO>>CC=O"})
build_compound_table(compound_ids: list[str]) dict[str, dict[str, Any]][source]#

Build a compound table for a list of KEGG compound identifiers.

Each returned record includes the KEGG compound identifier, the primary compound name, the optional MOL block, and a canonical SMILES string derived from the MOL block when RDKit parsing succeeds.

Parameters:

compound_ids (list[str]) – KEGG compound identifiers.

Returns:

Compound table of the form {cid: {"id", "name", "smiles", "molblock"}}.

Return type:

dict[str, dict[str, Any]]

Example#

compounds = extractor.build_compound_table(["C00001", "C00002"])
build_kegg_json(equations_by_rid: dict[str, str | None], *, smiles_by_rid: Mapping[str, str] | None = None, rules_by_rid: Mapping[str, str | None] | None = None, molecules_by_cid: Mapping[str, Mapping[str, Any]] | None = None) dict[str, Any][source]#

Build a compact KEGG JSON block with reactions and molecules.

Parameters:
  • equations_by_rid (dict[str, Optional[str]]) – Reaction equations keyed by reaction identifier.

  • smiles_by_rid (Optional[Mapping[str, str]]) – Optional reaction SMILES keyed by reaction identifier.

  • rules_by_rid (Optional[Mapping[str, Optional[str]]]) – Optional atom-mapped reaction strings keyed by reaction identifier.

  • molecules_by_cid (Optional[Mapping[str, Mapping[str, Any]]]) – Optional molecule table keyed by compound identifier.

Returns:

Dictionary with "reactions" and "molecules" entries.

Return type:

dict[str, Any]

Example#

data = extractor.build_kegg_json(equations_by_rid)
build_missing_compound_report(equations_by_rid: dict[str, str | None], compounds_by_cid: Mapping[str, Mapping[str, Any]]) dict[str, Any][source]#

Build a report for compounds lacking SMILES.

Parameters:
  • equations_by_rid (dict[str, Optional[str]]) – Reaction equations keyed by reaction identifier.

  • compounds_by_cid (Mapping[str, Mapping[str, Any]]) – Compound records keyed by KEGG compound identifier.

Returns:

Report containing missing compounds and per-reaction provenance.

Return type:

dict[str, Any]

Example#

report = extractor.build_missing_compound_report(
    equations_by_rid,
    compounds_by_cid,
)
build_module_json(module_id: str, *, with_compounds: bool = True, with_atom_maps: bool = True, save_as: str | None = None) dict[str, Any][source]#

Build a JSON block for a KEGG module.

Parameters:
  • module_id (str) – KEGG module ID.

  • with_compounds (bool) – Whether to resolve compound names, MOL blocks, and SMILES strings.

  • with_atom_maps (bool) – Whether to compute atom-mapped reactions.

  • save_as (Optional[str]) – Optional output path for writing the JSON block to disk.

Returns:

Module JSON dictionary.

Return type:

dict[str, Any]

Example#

data = extractor.build_module_json(
    "M00001",
    with_compounds=True,
    with_atom_maps=False,
)
build_pathway_json(pathway_id: str, *, with_compounds: bool = True, with_atom_maps: bool = True, save_as: str | None = None) dict[str, Any][source]#

Build a JSON block for a KEGG pathway, organized by module.

Parameters:
  • pathway_id (str) – KEGG pathway ID.

  • with_compounds (bool) – Whether to resolve compound records.

  • with_atom_maps (bool) – Whether to compute atom-mapped reactions.

  • save_as (Optional[str]) – Optional output path for writing the JSON block to disk.

Returns:

Pathway JSON dictionary.

Return type:

dict[str, Any]

Example#

data = extractor.build_pathway_json(
    "hsa00010",
    with_compounds=True,
    with_atom_maps=False,
)
build_reaction_smiles_dict(parsed_by_rid: Mapping[str, Any], compounds_by_cid: Mapping[str, Mapping[str, Any]]) tuple[dict[str, str], dict[str, dict[str, list[str]]]][source]#

Build reaction SMILES strings for parsed KEGG equations.

Parameters:
  • parsed_by_rid (Mapping[str, Any]) – Parsed equation objects keyed by reaction identifier.

  • compounds_by_cid (Mapping[str, Mapping[str, Any]]) – Compound table keyed by KEGG compound identifier.

Returns:

Tuple (reaction_smiles_by_id, missing_by_id).

Return type:

tuple[dict[str, str], dict[str, dict[str, list[str]]]]

Example#

rsmi_by_rid, missing = extractor.build_reaction_smiles_dict(
    parsed_by_rid,
    compounds_by_cid,
)
client: KEGGClient | None#
get_compound_molblock(compound_id: str) str | None[source]#

Retrieve the KEGG MOL block for a compound.

Parameters:

compound_id (str) – KEGG compound identifier.

Returns:

MOL block text when available, otherwise None.

Return type:

Optional[str]

Example#

molblock = extractor.get_compound_molblock("C00001")
get_compound_name(compound_id: str) str | None[source]#

Retrieve the primary KEGG compound name.

When multiple synonyms are present in the NAME field, only the first entry is returned.

Parameters:

compound_id (str) – KEGG compound identifier such as "C00001".

Returns:

Primary compound name if available, otherwise None.

Return type:

Optional[str]

Example#

name = extractor.get_compound_name("C00001")
get_equation_for_reaction(reaction_id: str) str | None[source]#

Fetch the KEGG equation string for a reaction.

Parameters:

reaction_id (str) – KEGG reaction identifier such as "R00200".

Returns:

Equation string when present, otherwise None.

Return type:

Optional[str]

Example#

equation = extractor.get_equation_for_reaction("R00200")
get_module_equations(module_id: str) dict[str, str | None][source]#

Build a reaction-to-equation mapping for a KEGG module.

Parameters:

module_id (str) – KEGG module identifier.

Returns:

Mapping from reaction identifier to equation string.

Return type:

dict[str, Optional[str]]

Example#

equations = extractor.get_module_equations("M00001")
get_modules_from_pathway(pathway_id: str) list[str][source]#

Extract module IDs from a KEGG pathway entry.

Parameters:

pathway_id (str) – KEGG pathway identifier such as "hsa00010".

Returns:

Canonical KEGG module identifiers such as ["M00001", "M00002"].

Return type:

list[str]

Example#

modules = extractor.get_modules_from_pathway("hsa00010")
get_pathway_equations(pathway_id: str) dict[str, dict[str, str | None]][source]#

Build nested module/reaction equation mappings for a pathway.

Parameters:

pathway_id (str) – KEGG pathway identifier.

Returns:

Mapping of the form {module_id: {reaction_id: equation}}.

Return type:

dict[str, dict[str, Optional[str]]]

Example#

nested = extractor.get_pathway_equations("hsa00010")
get_reaction_ids_from_module(module_id: str) list[str][source]#

Collect KEGG reaction IDs from a module entry, preserving module order when directional REACTION lines can be parsed.

Parameters:

module_id (str) – KEGG module identifier such as "M00001".

Returns:

Sorted unique KEGG reaction identifiers.

Return type:

list[str]

Example#

reaction_ids = extractor.get_reaction_ids_from_module("M00001")
mapper_cls: type[Any] | None#
static save_json(data: Mapping[str, Any], save_as: str | None) None[source]#

Save JSON data to disk when an output path is provided.

Parameters:
  • data (Mapping[str, Any]) – JSON-serializable data to write.

  • save_as (Optional[str]) – Optional output path.

Returns:

None.

Return type:

None

Example#

KEGGExtractor._save_json({"x": 1}, "out.json")
class synkit.CRN.Query.kegg_impute.KEGGImputer(extractor: KEGGExtractor | None = None)[source]#

Bases: object

Impute missing compound SMILES and repair reaction records in KEGG-style module or pathway JSON blocks.

The imputer supports two fix types through the same fixes argument:

  • molecule fixes, for example {"id": "C00404a", "smiles": "..."}

  • reaction fixes, for example {"id": "R02189", "reaction": "C00404 + C00267 <=> C00404a + C00668"}

Reaction fixes are applied first, then molecule fixes are applied, and finally impacted reaction SMILES, atom-mapped rules, and missing-compound summaries are rebuilt.

Parameters:

extractor (Optional[KEGGExtractor]) – Optional high-level KEGG extractor used for atom-mapping utilities and missing-compound report generation. When omitted, a default KEGGExtractor instance is created.

Example#

imputer = KEGGImputer()
updated = imputer.impute_module(
    module_data,
    fixes=[
        {
            "id": "R02189",
            "reaction": "C00404 + C00267 <=> C00404a + C00668",
        },
        {
            "id": "C00404a",
            "name": "Polyphosphate fragment",
            "smiles": "O=P(O)(O)OP(=O)(O)O",
        },
    ],
)
extractor: KEGGExtractor | None = None#
impute_module(module_data: Dict[str, Any], fixes: List[Dict[str, str]], save_as: str | None = None, *, molecule_id_key: str = 'id', reaction_id_key: str = 'id', equation_key: str = 'reaction', reaction_smiles_key: str = 'smiles', reaction_rule_key: str = 'rule') Dict[str, Any][source]#

Apply molecule and reaction fixes to a module JSON block.

Reaction fixes are applied first, then molecule fixes are applied, then impacted reaction SMILES and atom-mapped rules are rebuilt, and finally the missing block is regenerated by delegating to KEGGExtractor.build_missing_compound_report().

Parameters:
  • module_data (Dict[str, Any]) – Module JSON dictionary.

  • fixes (List[Dict[str, str]]) – List of mixed fix records. Reaction fixes must contain the reaction identifier key and the equation key. Molecule fixes use molecule identifiers and optional "name" / "smiles" fields.

  • save_as (Optional[str]) – Optional output path.

  • molecule_id_key (str) – Molecule identifier key.

  • reaction_id_key (str) – Reaction identifier key.

  • equation_key (str) – Equation text key.

  • reaction_smiles_key (str) – Reaction SMILES field key.

  • reaction_rule_key (str) – Atom-mapped rule field key.

Returns:

Updated module JSON dictionary.

Return type:

Dict[str, Any]

Example#

updated = imputer.impute_module(
    module_data,
    fixes=[
        {
            "id": "R02189",
            "reaction": "C00404 + C00267 <=> C00404a + C00668",
        },
        {
            "id": "C00404a",
            "name": "Polyphosphate fragment",
            "smiles": "O=P(O)(O)OP(=O)(O)O",
        },
    ],
)
impute_pathway(pathway_data: Dict[str, Any], fixes: List[Dict[str, str]], save_as: str | None = None, *, molecule_id_key: str = 'id', reaction_id_key: str = 'id', equation_key: str = 'reaction', reaction_smiles_key: str = 'smiles', reaction_rule_key: str = 'rule') Dict[str, Any][source]#

Apply molecule and reaction fixes across all modules in a pathway JSON block.

Each module is processed independently through impute_module(), then the pathway-level missing summary is rebuilt by aggregating the updated module summaries.

Parameters:
  • pathway_data (Dict[str, Any]) – Pathway JSON dictionary with "by_module".

  • fixes (List[Dict[str, str]]) – Mixed reaction and molecule fix records.

  • save_as (Optional[str]) – Optional output path.

  • molecule_id_key (str) – Molecule identifier key.

  • reaction_id_key (str) – Reaction identifier key.

  • equation_key (str) – Equation text key.

  • reaction_smiles_key (str) – Reaction SMILES field key.

  • reaction_rule_key (str) – Atom-mapped rule field key.

Returns:

Updated pathway JSON dictionary.

Return type:

Dict[str, Any]

Example#

updated = imputer.impute_pathway(
    pathway_data,
    fixes=[
        {
            "id": "R02189",
            "reaction": "C00404 + C00267 <=> C00404a + C00668",
        },
        {
            "id": "C00404a",
            "name": "Polyphosphate fragment",
            "smiles": "O=P(O)(O)OP(=O)(O)O",
        },
    ],
)
class synkit.CRN.Query.kegg_parse.KEGGEquation(reactants: list[tuple[str, int]], products: list[tuple[str, int]], reversible: bool)[source]#

Bases: object

Structured representation of a parsed KEGG reaction equation.

Parameters:
  • reactants (list[tuple[str, int]]) – Left-hand side of the equation as (compound_id, stoichiometry) pairs.

  • products (list[tuple[str, int]]) – Right-hand side of the equation as (compound_id, stoichiometry) pairs.

  • reversible (bool) – Whether the original equation used the reversible arrow <=>.

Example#

equation = KEGGEquation(
    reactants=[("C00001", 1), ("C00002", 2)],
    products=[("C00008", 1)],
    reversible=False,
)
products: list[tuple[str, int]]#
reactants: list[tuple[str, int]]#
reversible: bool#
synkit.CRN.Query.kegg_parse.equation_to_text(parsed: KEGGEquation, arrow: str | None = None) str[source]#

Convert KEGGEquation back to text, optionally forcing the arrow from the module hint.

synkit.CRN.Query.kegg_parse.expand_stoichiometry(items: Sequence[tuple[str, int]]) list[str][source]#

Expand stoichiometric pairs into repeated KEGG compound identifiers.

For example, [("C00001", 2), ("C00002", 1)] becomes ["C00001", "C00001", "C00002"].

Parameters:

items (Sequence[tuple[str, int]]) – Compound/coefficient pairs.

Returns:

Expanded compound identifier list.

Return type:

list[str]

Example#

expanded = expand_stoichiometry([("C00001", 2), ("C00002", 1)])
synkit.CRN.Query.kegg_parse.get_compound_ids_from_equations(equations_by_rid: Mapping[str, str | None]) tuple[list[str], dict[str, KEGGEquation]][source]#

Collect all compound identifiers appearing across KEGG reaction equations.

Empty or missing equation strings are skipped.

Parameters:

equations_by_rid (Mapping[str, Optional[str]]) – Mapping from reaction identifier to KEGG equation string.

Returns:

A tuple containing the sorted unique compound identifiers and the parsed equations keyed by reaction identifier.

Return type:

tuple[list[str], dict[str, KEGGEquation]]

Example#

compound_ids, parsed = get_compound_ids_from_equations(
    {"R00001": "C00001 + C00002 => C00003"}
)
synkit.CRN.Query.kegg_parse.get_compound_ids_from_text(text: str) list[str][source]#

Extract sorted unique KEGG compound identifiers from free text.

Parameters:

text (str) – Source text that may contain KEGG compound identifiers.

Returns:

Sorted unique KEGG compound identifiers.

Return type:

list[str]

Example#

ids = get_compound_ids_from_text("C00001 and C00002 appear here")
synkit.CRN.Query.kegg_parse.molblock_to_smiles(molblock: str | None) str | None[source]#

Convert a MOL block into canonical RDKit SMILES.

Parameters:

molblock (Optional[str]) – MOL block text, typically retrieved from a KEGG compound record.

Returns:

Canonical RDKit SMILES when parsing succeeds, otherwise None.

Return type:

Optional[str]

Example#

smiles = molblock_to_smiles(molblock_text)
synkit.CRN.Query.kegg_parse.normalize_module_id(module_id: str) str | None[source]#

Normalize a token to canonical KEGG module form.

Supported examples include strings such as "hsa_M00001" and "M00001", both of which normalize to "M00001".

Parameters:

module_id (str) – Raw module token or containing text.

Returns:

Canonical KEGG module identifier, or None when no module identifier is present.

Return type:

Optional[str]

Example#

canonical = normalize_module_id("hsa_M00001")
synkit.CRN.Query.kegg_parse.orient_equation_to_module(parsed: KEGGEquation, left_ids: list[str], right_ids: list[str]) KEGGEquation[source]#

Orient a parsed KEGG equation according to module direction.

synkit.CRN.Query.kegg_parse.parse_equation(equation: str) KEGGEquation[source]#

Parse a KEGG equation string into reactants, products, and arrow type.

Supported arrows are <=>, <->, =>, ->, <=, and <-.

Parameters:

equation (str) – KEGG equation string.

Returns:

Parsed equation object.

Return type:

KEGGEquation

Raises:

ValueError – Raised when the equation does not contain a supported KEGG arrow.

Example#

parsed = parse_equation("C00001 + C00002 <=> C00003")
synkit.CRN.Query.kegg_parse.parse_kegg_field_blocks(text: str, field: str) list[str][source]#

Extract payloads from a KEGG flatfile field, including continuation lines.

Continuation lines are recognized as lines beginning with spaces or tabs and are concatenated to the payload of the preceding field occurrence.

param text:

Raw KEGG flatfile text.

type text:

str

param field:

Flatfile field name such as "MODULE", "REACTION", "EQUATION", or "NAME".

type field:

str

returns:

One payload string per matching field occurrence.

rtype:

list[str]

text = (
    "MODULE      M00001 Glycolysis

“ continuation line

) payloads = parse_kegg_field_blocks(text, “MODULE”)

synkit.CRN.Query.kegg_parse.parse_module_reaction_directions(text: str) dict[str, tuple[list[str], list[str], str]][source]#

Parse directional hints from a KEGG MODULE entry.

Returns#

dict

Mapping: {

reaction_id: (left_compound_ids, right_compound_ids, arrow)

}

synkit.CRN.Query.kegg_parse.parse_side(side: str) list[tuple[str, int]][source]#

Parse one side of a KEGG equation into compound/stoichiometry pairs.

For example, "2 C00139 + C00001" becomes [("C00139", 2), ("C00001", 1)].

Parameters:

side (str) – One side of a KEGG equation.

Returns:

Parsed (compound_id, coefficient) pairs.

Return type:

list[tuple[str, int]]

Raises:

ValueError – Raised when any term does not match KEGG compound-stoichiometry syntax.

Example#

items = parse_side("2 C00139 + C00001")
synkit.CRN.Query.kegg_parse.reaction_smiles_from_equation(parsed_equation: KEGGEquation, compounds_by_cid: Mapping[str, Mapping[str, Any]]) tuple[str, dict[str, list[str]]][source]#

Build reaction SMILES from a parsed KEGG equation and compound table.

Stoichiometric multiplicities are expanded into repeated SMILES fragments. Missing compounds are reported separately for reactants and products.

Parameters:
  • parsed_equation (KEGGEquation) – Parsed KEGG equation object.

  • compounds_by_cid (Mapping[str, Mapping[str, Any]]) – Compound table keyed by KEGG compound identifier. Each record should provide a "smiles" entry.

Returns:

Tuple (reaction_smiles, missing) where missing contains lists of unresolved reactant and product KEGG compound identifiers.

Return type:

tuple[str, dict[str, list[str]]]

Example#

parsed = parse_equation("C00001 + C00002 => C00003")
reaction_smiles, missing = reaction_smiles_from_equation(
    parsed,
    {
        "C00001": {"smiles": "O"},
        "C00002": {"smiles": "CCO"},
        "C00003": {"smiles": "CC(=O)O"},
    },
)

Symmetry#

class synkit.CRN.Symmetry.automorphism.CRNAutomorphism(source: Any, *, include_rule: bool = True, include_stoich: bool = True, wl_iters: int = 20, wl_digest_size: int = 16, config: SymmetryConfig | None = None)[source]#

Bases: object

Exact automorphism analysis for a chemical reaction network graph.

This class provides a convenient public interface for exact automorphism queries, orbit extraction, and quick nontrivial-symmetry checks. When possible, it reuses an existing exact canonicalization engine so that canonicalization and automorphism queries share the same cached search.

Parameters:
  • source (Any) – Input source. This may be: - a CRN-like object - a NetworkX graph - an existing CRNCanonicalizer - an existing IRCanonicalEngine

  • include_rule (bool) – Whether rule/reaction nodes should be included when constructing the internal graph representation.

  • include_stoich (bool) – Whether stoichiometric information should be included in the internal representation.

  • wl_iters (int) – Maximum number of Weisfeiler-Lehman refinement iterations.

  • wl_digest_size (int) – Digest size used by the WL canonicalizer.

  • config (Optional[SymmetryConfig]) – Symmetry configuration controlling semantic versus topological matching. If None, SymmetryConfig.semantic() is used.

Notes#

For best performance, construct a CRNCanonicalizer first and pass it here so canonicalization and automorphism queries reuse the same cached exact search engine.

Examples#

from synkit.CRN.Sym.auto import CRNAutomorphism

auto = CRNAutomorphism(crn)
print(auto.has_nontrivial_automorphism())
print(auto.orbits())

summary = auto.summary(max_count=50, timeout_sec=10.0)
print(summary.automorphism_count)
property G: DiGraph#

Return the internal directed graph used for analysis.

Returns:

Internal directed graph.

Return type:

nx.DiGraph

automorphisms_iter(*, max_count: int | None = None, timeout_sec: float | None = None) Iterator[Dict[Any, Any]][source]#

Iterate over sampled automorphism mappings.

This method delegates to the exact IR engine and yields the sampled automorphism mappings that were collected during the search.

Parameters:
  • max_count (Optional[int]) – Optional maximum number of mappings to collect.

  • timeout_sec (Optional[float]) – Optional timeout in seconds.

Yields:

Automorphism mappings as node -> node dictionaries.

Return type:

Iterator[Dict[Any, Any]]

Examples#

auto = CRNAutomorphism(crn)
for mapping in auto.automorphisms_iter(max_count=5):
    print(mapping)
property graph_type: str#

Return the graph type label.

Returns:

Graph type string.

Return type:

str

has_nontrivial_automorphism(*, timeout_sec: float | None = 5.0) bool[source]#

Check whether the graph has a nontrivial automorphism.

A fast WL-based orbit test is used first. If WL leaves no ambiguous cells, the graph is treated as having no nontrivial automorphism. Otherwise, an exact search is run and stopped after two equivalent automorphisms are found.

Parameters:

timeout_sec (Optional[float]) – Optional timeout in seconds for the exact fallback check.

Returns:

True if a nontrivial automorphism exists.

Return type:

bool

orbits(*, max_count: int = 1000, timeout_sec: float | None = 5.0) List[Set[Any]][source]#

Compute orbit classes from sampled automorphisms.

Parameters:
  • max_count (int) – Maximum number of sampled mappings to retain.

  • timeout_sec (Optional[float]) – Optional timeout in seconds.

Returns:

Orbit partition induced by the sampled automorphisms.

Return type:

List[Set[Any]]

summary(*, max_count: int = 100, timeout_sec: float | None = 5.0) AutomorphismResult[source]#

Compute an automorphism summary.

Parameters:
  • max_count (int) – Maximum number of sampled mappings to retain.

  • timeout_sec (Optional[float]) – Optional timeout in seconds.

Returns:

Automorphism summary result.

Return type:

AutomorphismResult

wl_orbits() List[Set[Any]][source]#

Return approximate WL color-class orbits.

These are faster but weaker than exact automorphism orbits.

Returns:

WL-based orbit partition.

Return type:

List[Set[Any]]

synkit.CRN.Symmetry.automorphism.detect_automorphisms(source: Any, *, max_count: int = 100, timeout_sec: float | None = 5.0, **kwargs: Any) AutomorphismResult[source]#

Convenience wrapper for automorphism detection.

Parameters:
  • source (Any) – Input source, canonicalizer, or engine.

  • max_count (int) – Maximum number of sampled mappings to retain.

  • timeout_sec (Optional[float]) – Optional timeout in seconds.

  • kwargs (Any) – Additional keyword arguments forwarded to CRNAutomorphism.

Returns:

Automorphism summary result.

Return type:

AutomorphismResult

Examples#

result = detect_automorphisms(crn, max_count=50, timeout_sec=10.0)
print(result.automorphism_count)
print(result.orbits)
class synkit.CRN.Symmetry.canon.CRNCanonicalizer(source: Any, *, include_rule: bool = True, include_stoich: bool = True, wl_iters: int = 20, wl_digest_size: int = 16, config: SymmetryConfig | None = None)[source]#

Bases: object

Exact canonicalizer and symmetry analyzer backed by one shared IR engine.

This is the preferred high-level entry point when a chemical reaction network or related graph-like source needs both:

  • a canonical form

  • exact automorphism information

  • orbit information for symmetric nodes

The class combines a fast Weisfeiler–Lehman (WL) based pre-analysis with an exact IR-based canonicalization backend. The underlying exact engine is shared across methods so intermediate work can be reused.

Parameters:
  • source (Any) – Input object to canonicalize. This is typically a SynCRN-like object or a graph representation accepted by the internal canonicalization engine.

  • include_rule (bool) – Whether rule / reaction nodes should be included explicitly in the canonicalization model.

  • include_stoich (bool) – Whether stoichiometric information should be included in the canonical representation and symmetry analysis.

  • wl_iters (int) – Number of WL refinement iterations used by the approximate canonicalizer.

  • wl_digest_size (int) – Digest size used for WL hashing.

  • config (Optional[SymmetryConfig]) – Optional symmetry / semantic configuration. If None, a semantic default configuration is used.

Example#

canon = CRNCanonicalizer(
    syncrn,
    include_rule=True,
    include_stoich=True,
)

key = canon.canonical_key()
orbits = canon.orbits()
has_symmetry = canon.has_nontrivial_automorphism()
property G: DiGraph#

Return the internal directed graph used by the exact engine.

Returns:

Internal graph representation.

Return type:

nx.DiGraph

automorphism_result(*, max_count: int = 100, timeout_sec: float | None = 5.0)[source]#

Return the exact automorphism analysis result.

The returned object depends on the internal engine and usually contains automorphism count, sample permutations, sample mappings, orbit information, and timing metadata.

Parameters:
  • max_count (int) – Maximum number of automorphisms to enumerate or track.

  • timeout_sec (Optional[float]) – Timeout in seconds for the exact search.

Returns:

Exact automorphism analysis result from the engine.

canonical_graph(*, timeout_sec: float | None = None) DiGraph[source]#

Return a canonically relabeled graph.

Nodes are relabeled according to the exact canonical order using consecutive integer labels starting from 1.

Parameters:

timeout_sec (Optional[float]) – Optional timeout in seconds.

Returns:

Canonically relabeled copy of the internal graph.

Return type:

nx.DiGraph

Example#

g_canon = canon.canonical_graph()
print(g_canon.nodes())
canonical_key(*, timeout_sec: float | None = None)[source]#

Return the exact canonical key.

The exact type depends on the underlying canonical engine.

Parameters:

timeout_sec (Optional[float]) – Optional timeout in seconds.

Returns:

Canonical key representing the isomorphism class of the source.

canonical_order(*, timeout_sec: float | None = None) List[Any][source]#

Return the exact canonical node order.

Parameters:

timeout_sec (Optional[float]) – Optional timeout in seconds.

Returns:

Canonical ordering of nodes.

Return type:

List[Any]

canonical_result(*, timeout_sec: float | None = None) CanonicalResult[source]#

Compute or retrieve the exact canonicalization result.

This method delegates to the shared exact engine and returns the full canonicalization result object, which typically includes the canonical order, canonical key, and timing information.

Parameters:

timeout_sec (Optional[float]) – Optional timeout in seconds for the exact canonicalization search. If None, the engine default behavior is used.

Returns:

Exact canonicalization result.

Return type:

CanonicalResult

Example#

res = canon.canonical_result(timeout_sec=5.0)
print(res.canonical_order)
print(res.canonical_key)
property engine: IRCanonicalEngine#

Return the shared exact IR canonicalization engine.

Returns:

Exact canonicalization / symmetry engine.

Return type:

IRCanonicalEngine

property graph_type: str#

Return a string describing the interpreted graph type.

Returns:

Graph type label reported by the engine.

Return type:

str

has_nontrivial_automorphism(*, timeout_sec: float | None = 5.0) bool[source]#

Test whether the source has a nontrivial automorphism.

A fast WL orbit partition is used as an early filter. If all WL orbits are singletons, the method immediately returns False. Otherwise an exact search is performed and the source is considered symmetric if the automorphism count is greater than 1.

Parameters:

timeout_sec (Optional[float]) – Timeout in seconds for the exact symmetry check.

Returns:

True if a non-identity automorphism exists, else False.

Return type:

bool

Example#

if canon.has_nontrivial_automorphism():
    print("Symmetry detected")
orbits(*, max_count: int = 1000, timeout_sec: float | None = 5.0) List[Set[Any]][source]#

Return exact node orbits under the automorphism group.

Nodes are in the same orbit if an automorphism can map one node to the other.

Parameters:
  • max_count (int) – Maximum number of automorphisms considered during the exact search.

  • timeout_sec (Optional[float]) – Timeout in seconds for the exact search.

Returns:

List of exact orbit sets.

Return type:

List[Set[Any]]

Example#

for orbit in canon.orbits():
    print(sorted(orbit))
summary(*, max_count: int = 100, timeout_sec: float | None = 5.0, include_automorphisms: bool = True) Dict[str, Any][source]#

Return a summary dictionary for canonicalization and symmetry analysis.

If include_automorphisms is True, the summary includes exact automorphism information, sample permutations, orbit data, and early-stop metadata. Otherwise only canonicalization data is returned.

Parameters:
  • max_count (int) – Maximum number of automorphisms to enumerate or track.

  • timeout_sec (Optional[float]) – Timeout in seconds for the exact search.

  • include_automorphisms (bool) – Whether to include exact automorphism-related information.

Returns:

Summary dictionary containing canonical and optionally symmetry information.

Return type:

Dict[str, Any]

Example#

info = canon.summary(include_automorphisms=True)
print(info["canonical_key"])
print(info["automorphism_count"])
wl_orbits() List[Set[Any]][source]#

Return WL-refined approximate orbit classes.

These are not guaranteed to equal the exact automorphism orbits, but they are often useful as a fast symmetry approximation or as a filter before running exact search.

Returns:

Approximate orbit partition from WL refinement.

Return type:

List[Set[Any]]

synkit.CRN.Symmetry.canon.canonical(source: Any, **kwargs: Any) DiGraph[source]#

Return the canonically relabeled graph for a source object.

This is a convenience wrapper around CRNCanonicalizer.

Parameters:
  • source (Any) – Input object to canonicalize.

  • kwargs (Any) – Additional keyword arguments forwarded to CRNCanonicalizer.

Returns:

Canonically relabeled directed graph.

Return type:

nx.DiGraph

Example#

g_canon = canonical(
    syncrn,
    include_rule=True,
    include_stoich=True,
)
class synkit.CRN.Symmetry.isomorphism.CRNIsomorphism(source: Any, *, include_rule: bool = True, include_stoich: bool = True, wl_iters: int = 20, wl_digest_size: int = 16, config: SymmetryConfig | None = None)[source]#

Bases: object

Pairwise graph isomorphism and subgraph isomorphism for CRN graphs.

This class wraps a CRN graph representation together with the node and edge matchers required for exact VF2-style isomorphism checks. It also provides a fast invariant-based rejection step using graph signatures derived from node tokens, edge tokens, degree histograms, and WL color histograms.

Parameters:
  • source (Any) – Input source accepted by WLCanonicalizer, such as a CRN-like object or a NetworkX graph.

  • include_rule (bool) – Whether rule/reaction nodes should be included in the internal graph representation.

  • include_stoich (bool) – Whether stoichiometric information should be included in the internal graph representation.

  • wl_iters (int) – Maximum number of Weisfeiler-Lehman refinement iterations.

  • wl_digest_size (int) – Digest size used by the WL canonicalizer.

  • config (Optional[SymmetryConfig]) – Symmetry configuration controlling semantic versus topological matching. If None, SymmetryConfig.semantic() is used.

Examples#

from synkit.CRN.Sym.iso import CRNIsomorphism

iso_a = CRNIsomorphism(crn_a)
iso_b = CRNIsomorphism(crn_b)

result = iso_a.isomorphic_to(iso_b)
print(result.isomorphic)
print(result.mapping)

sub = iso_a.subgraph_isomorphic_to(iso_b)
print(sub.isomorphic)
property G: DiGraph#

Return the internal directed graph.

Returns:

Internal directed graph used for isomorphism analysis.

Return type:

nx.DiGraph

property graph_type: str#

Return the graph type label.

Returns:

Graph type string.

Return type:

str

isomorphic_to(other: CRNIsomorphism) IsomorphismResult[source]#

Test graph isomorphism against another CRN isomorphism wrapper.

A fast signature check is applied first. If signatures disagree, the graphs are rejected immediately without invoking the exact VF2 matcher.

Parameters:

other (CRNIsomorphism) – Other graph wrapper to compare against.

Returns:

Exact isomorphism result.

Return type:

IsomorphismResult

Examples#

iso_a = CRNIsomorphism(crn_a)
iso_b = CRNIsomorphism(crn_b)
result = iso_a.isomorphic_to(iso_b)
print(result.isomorphic)
subgraph_isomorphic_to(host: CRNIsomorphism) IsomorphismResult[source]#

Test whether this graph is subgraph-isomorphic to a host graph.

This method checks whether self can be embedded into host using directed VF2 subgraph matching.

Parameters:

host (CRNIsomorphism) – Host graph wrapper.

Returns:

Subgraph isomorphism result.

Return type:

IsomorphismResult

Examples#

pattern = CRNIsomorphism(pattern_crn)
host = CRNIsomorphism(host_crn)
result = pattern.subgraph_isomorphic_to(host)
print(result.isomorphic)
synkit.CRN.Symmetry.isomorphism.are_isomorphic(a: Any, b: Any, **kwargs: Any) bool[source]#

Convenience wrapper for pairwise graph isomorphism.

Parameters:
  • a (Any) – First graph-like source.

  • b (Any) – Second graph-like source.

  • kwargs (Any) – Additional keyword arguments forwarded to CRNIsomorphism.

Returns:

True if the two inputs are isomorphic.

Return type:

bool

Examples#

ok = are_isomorphic(crn_a, crn_b, include_rule=True)
print(ok)
synkit.CRN.Symmetry.isomorphism.are_subhypergraph_isomorphic(pattern: Any, host: Any, **kwargs: Any) bool[source]#

Convenience wrapper for subgraph isomorphism.

Parameters:
  • pattern (Any) – Pattern graph-like source.

  • host (Any) – Host graph-like source.

  • kwargs (Any) – Additional keyword arguments forwarded to CRNIsomorphism.

Returns:

True if pattern is subgraph-isomorphic to host.

Return type:

bool

Examples#

ok = are_subhypergraph_isomorphic(pattern_crn, host_crn)
print(ok)
class synkit.CRN.Symmetry.symmetry.CRNSymmetry(source: Any, *, include_rule: bool = True, include_stoich: bool = True, wl_iters: int = 20, wl_digest_size: int = 16, config: SymmetryConfig | None = None)[source]#

Bases: object

Unified façade for WL, automorphism, canonicalization, and isomorphism.

automorphism_summary(**kwargs: Any)[source]#
canonical_graph(**kwargs: Any)[source]#
canonical_result(**kwargs: Any)[source]#
has_nontrivial_automorphism(**kwargs: Any)[source]#
orbits(**kwargs: Any)[source]#
wl_orbits()[source]#
class synkit.CRN.Symmetry.wl_canon.WLCanonicalResult(canon_graph: DiGraph, graph_type: str, canonical_order: List[Any], canonical_key: Any, automorphism_count: int | None, orbits: List[Set[Any]], colors: Dict[Any, str], color_hist: Dict[str, int], iters_run: int, stabilized: bool, exact: bool, elapsed_seconds: float)[source]#

Bases: object

Approximate canonicalization result from WL refinement.

This mirrors the exact canonicalizer style, but remains approximate.

Parameters:
  • canon_graph (nx.DiGraph) – Graph canonically relabeled according to the WL order.

  • graph_type (str) – Graph representation type, e.g. "bipartite" or "species".

  • canonical_order (List[Any]) – Deterministic node order induced by the final WL partition.

  • canonical_key (Any) – Canonical graph key derived from the WL order.

  • automorphism_count (Optional[int]) – Approximate automorphism count from WL cells.

  • orbits (List[Set[Any]]) – Approximate node orbits from the final WL cells.

  • colors (Dict[Any, str]) – Final WL color mapping.

  • color_hist (Dict[str, int]) – Histogram of final WL colors.

  • iters_run (int) – Number of WL iterations actually performed.

  • stabilized (bool) – Whether WL refinement stabilized before the maximum iteration count.

  • exact (bool) – Always False for WL refinement.

  • elapsed_seconds (float) – Runtime in seconds for building the result object.

automorphism_count: int | None#
canon_graph: DiGraph#
canonical_key: Any#
canonical_order: List[Any]#
color_hist: Dict[str, int]#
colors: Dict[Any, str]#
elapsed_seconds: float#
exact: bool#
graph_type: str#
iters_run: int#
orbits: List[Set[Any]]#
stabilized: bool#
class synkit.CRN.Symmetry.wl_canon.WLCanonicalizer(source: Any, *, include_rule: bool = True, include_stoich: bool = True, n_iter: int = 20, digest_size: int = 16, include_in_neighbors: bool = True, include_out_neighbors: bool = True, estimate_automorphisms: bool = True, automorphism_cap: int = 1000000000000000000, config: SymmetryConfig | None = None)[source]#

Bases: object

Fast approximate canonicalizer for SynKit CRN graphs using direction-aware 1-WL refinement.

This class is designed as a lightweight companion to the exact CRN canonicalizer. It gives:

  • deterministic WL-based canonical relabeling

  • approximate orbit partitions

  • approximate automorphism counts from WL cells

  • fast signatures for cheap prefiltering

Compared with the exact canonicalizer, this class is much faster but not guaranteed to distinguish all non-isomorphic graphs or recover exact automorphism groups.

Parameters:
  • source (Any) – Input CRN representation. This may be a prepared networkx.DiGraph, an object exposing to_digraph(), or any object accepted by prepare_graph().

  • include_rule (bool) – Whether rule nodes should be included in the prepared graph.

  • include_stoich (bool) – Whether stoichiometric edge attributes should be preserved during graph preparation.

  • n_iter (int) – Maximum number of WL refinement iterations.

  • digest_size (int) – Digest size used when hashing node and edge signatures.

  • include_in_neighbors (bool) – Whether incoming neighbors should contribute to refinement.

  • include_out_neighbors (bool) – Whether outgoing neighbors should contribute to refinement.

  • estimate_automorphisms (bool) – Whether to compute an approximate automorphism count from the final WL cells.

  • automorphism_cap (int) – Cap applied to approximate automorphism counts.

  • config (Optional[SymmetryConfig]) – Symmetry semantics configuration controlling which node and edge attributes participate in WL coloring.

Example#

from synkit.CRN.Sym import WLCanonicalizer, SymmetryConfig

wl = WLCanonicalizer(
    syn.to_digraph(),
    include_rule=True,
    config=SymmetryConfig.topological(),
)

print(wl.has_nontrivial_automorphism())
print(wl.orbits())
print(wl.canonical_order())
print(wl.summary()["automorphism_count"])
property G: DiGraph#

Return the prepared graph.

Returns:

Prepared directed graph.

Return type:

nx.DiGraph

Example#

wl = WLCanonicalizer(syn)
print(wl.G.number_of_nodes(), wl.G.number_of_edges())
canonical_graph() DiGraph[source]#

Return the canonically relabeled graph using the WL order.

Returns:

WL-canonically relabeled graph.

Return type:

nx.DiGraph

Example#

wl = WLCanonicalizer(syn)
G_can = wl.canonical_graph()
print(sorted(G_can.nodes()))
canonical_key() Any[source]#

Return the canonical key induced by the WL order.

Returns:

WL canonical key.

Return type:

Any

Example#

wl = WLCanonicalizer(syn)
print(wl.canonical_key())
canonical_order() List[Any][source]#

Return the deterministic WL node order.

Returns:

WL-based canonical node order.

Return type:

List[Any]

Example#

wl = WLCanonicalizer(syn)
print(wl.canonical_order())
canonical_result() WLCanonicalResult[source]#

Build an approximate canonicalization result in a CRN-canon-like format.

Returns:

Approximate canonicalization result.

Return type:

WLCanonicalResult

Example#

wl = WLCanonicalizer(syn)
result = wl.canonical_result()
print(result.canonical_order)
print(result.automorphism_count)
color_of(v: Any) str[source]#

Return the final WL color of one node.

Parameters:

v (Any) – Node identifier.

Returns:

Final WL color.

Return type:

str

Example#

wl = WLCanonicalizer(syn)
print(wl.color_of(1))
colors() Dict[Any, str][source]#

Return final WL colors.

Returns:

Mapping from node to final color.

Return type:

Dict[Any, str]

Example#

wl = WLCanonicalizer(syn)
print(wl.colors())
fast_signature() Tuple[Any, ...][source]#

Return a fast graph signature using graph statistics and WL color histogram.

This is useful as a cheap prefilter before exact graph isomorphism or exact canonicalization.

Returns:

Fast graph signature.

Return type:

Tuple[Any, …]

Example#

wl = WLCanonicalizer(syn)
print(wl.fast_signature())
graph() DiGraph[source]#

Alias for canonical_graph(), matching the older canon style.

Returns:

WL-canonically relabeled graph.

Return type:

nx.DiGraph

Example#

wl = WLCanonicalizer(syn)
G_can = wl.graph()
property graph_type: str#

Return the graph representation type.

Returns:

Graph representation type.

Return type:

str

Example#

wl = WLCanonicalizer(syn, include_rule=True)
print(wl.graph_type)
has_nontrivial_automorphism() bool[source]#

Heuristically detect whether symmetry may be present.

This is approximate and simply checks whether any WL color cell has size greater than one.

Returns:

True if WL detects a non-singleton cell, else False.

Return type:

bool

Example#

wl = WLCanonicalizer(syn)
print(wl.has_nontrivial_automorphism())
orbits() List[Set[Any]][source]#

Return approximate WL orbit sets.

Returns:

Approximate orbits induced by final WL colors.

Return type:

List[Set[Any]]

Example#

wl = WLCanonicalizer(syn)
print(wl.orbits())
summary() Dict[str, Any][source]#

Return a dictionary summary in a format close to the exact canonicalizer.

The reported automorphism count and orbit sets are WL-based approximations.

Returns:

Summary dictionary.

Return type:

Dict[str, Any]

Example#

wl = WLCanonicalizer(syn)
info = wl.summary()
print(info["automorphism_count"])
print(info["orbits"])
wl_orbits() List[Set[Any]][source]#

Alias for orbits().

Returns:

Approximate WL orbit sets.

Return type:

List[Set[Any]]

synkit.CRN.Symmetry.wl_canon.wl_canonical(source: Any, **kwargs: Any) DiGraph[source]#

Convenience function returning the WL-canonically relabeled graph.

Parameters:
  • source (Any) – Input CRN representation.

  • kwargs (Any) – Additional keyword arguments forwarded to WLCanonicalizer.

Returns:

WL-canonically relabeled graph.

Return type:

nx.DiGraph

Example#

from synkit.CRN.Sym import SymmetryConfig, wl_canonical

G_can = wl_canonical(
    syn.to_digraph(),
    include_rule=True,
    config=SymmetryConfig.topological(),
)

Visualization#

class synkit.CRN.Visualize.crn_vis.CRNVis(graph: DiGraph, layout: str = 'bipartite', species_label: str = 'index', rule_label: str = 'name', font_size: int = 6)[source]#

Bases: object

Lightweight visualizer for CRN-style DAGs built by DAG.

The visualizer expects a directed bipartite graph where:

  • Species nodes have kind='species' and a smiles attribute.

  • Rule nodes have kind='rule' and rule_index / rule_name attributes.

  • Edges are annotated with role='reactant' or role='product'.

Parameters:
  • graph (networkx.DiGraph) – Directed CRN graph to visualize.

  • layout (str) – Layout strategy. "bipartite" places species on the left and rules on the right; "spring" uses networkx.spring_layout().

  • species_label (str) – Label type for species nodes, either "index" (node id) or "smiles" (SMILES string).

  • rule_label (str) – Label type for rule nodes, either "name" (rule_name) or "index" (r{rule_index}).

  • font_size (int) – Font size for node labels.

draw(ax: 'matplotlib.axes.Axes' | None = None, show: bool = False)[source]#

Draw the CRN DAG using matplotlib.

Species nodes are drawn as circles, rule nodes as squares. Reactant edges (species→rule) are dashed; product edges (rule→species) are solid.

Parameters:
  • ax (matplotlib.axes.Axes or None) – Optional matplotlib axes to draw on. If None, a new figure and axes are created.

  • show (bool) – If True, call matplotlib.pyplot.show() at the end.

Returns:

Tuple of (figure, axes) used for drawing.

Return type:

(matplotlib.figure.Figure, matplotlib.axes.Axes)

font_size: int = 6#
graph: DiGraph#
layout: str = 'bipartite'#
rule_label: str = 'name'#
species_label: str = 'index'#
synkit.CRN.Visualize.labels.build_edge_labels(graph: DiGraph, *, mode: str = 'none', max_chars: int | None = 20) Dict[tuple[Hashable, Hashable], str][source]#
synkit.CRN.Visualize.labels.build_node_labels(graph: DiGraph, *, species_nodes: Iterable[Hashable], rule_nodes: Iterable[Hashable], species_label: str = 'label', rule_label: str = 'label', show_species_labels: bool = True, show_rule_labels: bool = True, max_chars: int | None = 32, wrap_at: int | None = None) Dict[Hashable, str][source]#
synkit.CRN.Visualize.layout.available_layouts() List[str][source]#

Return the list of supported layout names.

Returns:

Supported layout names, including "auto".

Return type:

List[str]

names = available_layouts()
print(names)
synkit.CRN.Visualize.layout.bipartite_layout(graph: DiGraph, *, species_nodes: List[Hashable], rule_nodes: List[Hashable], node_spacing: float = 1.4, layer_spacing: float = 3.0, orientation: str = 'vertical') Dict[Hashable, Tuple[float, float]][source]#

Compute a two-layer species-rule layout.

Parameters:
  • graph (nx.DiGraph) – Directed graph containing species and rule nodes.

  • species_nodes (List[Hashable]) – List of species node identifiers.

  • rule_nodes (List[Hashable]) – List of rule node identifiers.

  • node_spacing (float) – Spacing between adjacent nodes within a layer.

  • layer_spacing (float) – Distance between the species and rule layers.

  • orientation (str) – Layout orientation. Must be "vertical" or "horizontal".

Returns:

Mapping from node identifier to (x, y) coordinates.

Return type:

Pos

Raises:

ValueError – If orientation is not supported.

synkit.CRN.Visualize.layout.choose_auto_layout(graph: DiGraph, *, species_nodes: List[Hashable], rule_nodes: List[Hashable]) str[source]#

Choose a layout heuristically.

Preference is given to step-aware layouts when rule step annotations are available. Larger or denser graphs are routed to layouts that typically reduce clutter.

Parameters:
  • graph (nx.DiGraph) – Directed graph containing species and rule nodes.

  • species_nodes (List[Hashable]) – List of species node identifiers.

  • rule_nodes (List[Hashable]) – List of rule node identifiers.

Returns:

Selected layout name.

Return type:

str

synkit.CRN.Visualize.layout.circular_bipartite_layout(graph: DiGraph, *, species_nodes: List[Hashable], rule_nodes: List[Hashable], species_radius: float = 2.5, rule_radius: float = 4.0) Dict[Hashable, Tuple[float, float]][source]#

Compute a circular bipartite layout using two concentric circles.

Species and rule nodes are placed on separate rings.

Parameters:
  • graph (nx.DiGraph) – Directed graph containing species and rule nodes.

  • species_nodes (List[Hashable]) – List of species node identifiers.

  • rule_nodes (List[Hashable]) – List of rule node identifiers.

  • species_radius (float) – Radius of the species ring.

  • rule_radius (float) – Radius of the rule ring.

Returns:

Mapping from node identifier to (x, y) coordinates.

Return type:

Pos

synkit.CRN.Visualize.layout.compute_layout(graph: DiGraph, *, species_nodes: List[Hashable], rule_nodes: List[Hashable], layout: str = 'step', node_spacing: float = 1.4, layer_spacing: float = 2.5, seed: int = 0, orientation: str = 'vertical') Dict[Hashable, Tuple[float, float]][source]#

Compute node positions for CRN visualization.

Parameters:
  • graph (nx.DiGraph) – Directed graph containing species and rule nodes.

  • species_nodes (List[Hashable]) – List of species node identifiers.

  • rule_nodes (List[Hashable]) – List of rule node identifiers.

  • layout (str) – Layout name. Supported values are "auto", "step", "bipartite", "multipartite_step", "radial_step", "circular_bipartite", "degree_shell", "spring", "kamada_kawai", "spectral", "shell", "spiral", and "random".

  • node_spacing (float) – Spacing between nodes within a layer for layouts that support it.

  • layer_spacing (float) – Spacing between layers for layouts that support it.

  • seed (int) – Random seed for stochastic layouts.

  • orientation (str) – Orientation for the bipartite layout. Must be "vertical" or "horizontal".

Returns:

Mapping from node identifier to (x, y) coordinates.

Return type:

Pos

Raises:

ValueError – If the requested layout name is not supported.

pos = compute_layout(
    graph,
    species_nodes=species_nodes,
    rule_nodes=rule_nodes,
    layout="auto",
)
synkit.CRN.Visualize.layout.degree_shell_layout(graph: DiGraph, *, species_nodes: List[Hashable], rule_nodes: List[Hashable]) Dict[Hashable, Tuple[float, float]][source]#

Compute a degree-based shell layout.

Nodes with the highest degree are placed in the inner shell, followed by medium-degree and lower-degree shells.

Parameters:
  • graph (nx.DiGraph) – Directed graph containing species and rule nodes.

  • species_nodes (List[Hashable]) – List of species node identifiers.

  • rule_nodes (List[Hashable]) – List of rule node identifiers.

Returns:

Mapping from node identifier to (x, y) coordinates.

Return type:

Pos

synkit.CRN.Visualize.layout.multipartite_step_layout(graph: DiGraph, *, species_nodes: List[Hashable], rule_nodes: List[Hashable]) Dict[Hashable, Tuple[float, float]][source]#

Compute a multipartite layout using inferred step layers.

This layout is useful for larger step-annotated graphs where a simple custom step layout becomes crowded.

Parameters:
  • graph (nx.DiGraph) – Directed graph containing species and rule nodes.

  • species_nodes (List[Hashable]) – List of species node identifiers.

  • rule_nodes (List[Hashable]) – List of rule node identifiers.

Returns:

Mapping from node identifier to (x, y) coordinates.

Return type:

Pos

synkit.CRN.Visualize.layout.radial_step_layout(graph: DiGraph, *, species_nodes: List[Hashable], rule_nodes: List[Hashable], radius_step: float = 1.8) Dict[Hashable, Tuple[float, float]][source]#

Compute a radial step layout using concentric circles.

Logical layers are mapped to increasing radii.

Parameters:
  • graph (nx.DiGraph) – Directed graph containing species and rule nodes.

  • species_nodes (List[Hashable]) – List of species node identifiers.

  • rule_nodes (List[Hashable]) – List of rule node identifiers.

  • radius_step (float) – Radial increment between adjacent logical layers.

Returns:

Mapping from node identifier to (x, y) coordinates.

Return type:

Pos

synkit.CRN.Visualize.layout.step_layout(graph: DiGraph, *, species_nodes: List[Hashable], rule_nodes: List[Hashable], node_spacing: float = 1.4, layer_spacing: float = 2.5) Dict[Hashable, Tuple[float, float]][source]#

Compute a layered step-wise layout.

Species and rule nodes are assigned to alternating logical x-layers inferred from rule steps and incidence relationships.

Parameters:
  • graph (nx.DiGraph) – Directed graph containing species and rule nodes.

  • species_nodes (List[Hashable]) – List of species node identifiers.

  • rule_nodes (List[Hashable]) – List of rule node identifiers.

  • node_spacing (float) – Vertical spacing between nodes in the same layer.

  • layer_spacing (float) – Horizontal spacing between adjacent layers.

Returns:

Mapping from node identifier to (x, y) coordinates.

Return type:

Pos

pos = step_layout(
    graph,
    species_nodes=species_nodes,
    rule_nodes=rule_nodes,
    node_spacing=1.6,
    layer_spacing=3.0,
)
class synkit.CRN.Visualize.palette.ColorPalette(background: str, species_fill: str, species_edge: str, rule_fill: str, rule_edge: str, reactant_edge: str, product_edge: str, other_edge: str, highlight_node: str, highlight_edge: str, label_text: str, node_index_text: str, legend_text: str, title_text: str)[source]#

Bases: object

Muted publication-style palette for CRN visualization.

The defaults are intentionally restrained: muted species and rule colors, light paper-like background, and neutral label text.

background: str#
highlight_edge: str#
highlight_node: str#
label_text: str#
legend_text: str#
node_index_text: str#
other_edge: str#
product_edge: str#
reactant_edge: str#
rule_edge: str#
rule_fill: str#
species_edge: str#
species_fill: str#
title_text: str#
with_overrides(**kwargs) ColorPalette[source]#
synkit.CRN.Visualize.palette.get_palette(name: str = 'paper_sage', **overrides) ColorPalette[source]#
synkit.CRN.Visualize.palette.palette_names() list[str][source]#
class synkit.CRN.Visualize.validation.CRNGraphInfo(species_nodes: 'List[Hashable]', rule_nodes: 'List[Hashable]', is_dag: 'bool')[source]#

Bases: object

is_dag: bool#
rule_nodes: List[Hashable]#
species_nodes: List[Hashable]#
synkit.CRN.Visualize.validation.node_sort_key(graph: DiGraph, node: Hashable)[source]#
synkit.CRN.Visualize.validation.validate_crn_graph(graph: DiGraph, *, strict: bool = True) CRNGraphInfo[source]#
class synkit.CRN.Visualize.vis.CRNStyle(figsize: Tuple[float, float] = (12.0, 7.0), species_node_shape: str = 'o', rule_node_shape: str = 's', species_node_size: int = 760, rule_node_size: int = 540, edge_width: float = 1.2, highlight_edge_width: float = 2.1, reactant_style: str = 'dashed', product_style: str = 'solid', other_style: str = 'solid', arrows: bool = True, arrowstyle: str = '-|>', arrowsize: int = 12, font_size: int = 8, alpha: float = 0.98, margins: float = 0.12, show_label_boxes: bool = False, label_box_alpha: float = 0.0, curved_edges: bool = False, curve_radius: float = 0.0, scale_edge_width_by_stoich: bool = True, stoich_width_factor: float = 0.4, linewidths: float = 1.0, highlight_linewidths: float = 1.6, edge_alpha: float = 0.9, node_alpha: float = 1.0, show_node_outline: bool = True, label_fontweight: str = 'regular', auto_reduce_labels_when_dense: bool = True, dense_node_threshold: int = 45, dense_edge_threshold: int = 70, dense_font_size: int = 7)[source]#

Bases: object

Visual style configuration for CRN plots.

The defaults are tuned for muted publication-style figures with straight edges, no label boxes, moderate alpha, and restrained line widths.

Parameters:
  • figsize (Tuple[float, float]) – Figure size in inches.

  • species_node_shape (str) – Matplotlib marker shape for species nodes.

  • rule_node_shape (str) – Matplotlib marker shape for rule nodes.

  • species_node_size (int) – Node size for species nodes.

  • rule_node_size (int) – Node size for rule nodes.

  • edge_width (float) – Base width for regular edges.

  • highlight_edge_width (float) – Width for highlighted edges.

  • reactant_style (str) – Line style for reactant edges.

  • product_style (str) – Line style for product edges.

  • other_style (str) – Line style for untyped edges.

  • arrows (bool) – Whether to draw arrows on edges.

  • arrowstyle (str) – Matplotlib arrow style string.

  • arrowsize (int) – Arrow size for directed edges.

  • font_size (int) – Default node label font size.

  • alpha (float) – General alpha value retained for backward compatibility.

  • margins (float) – Plot margins passed to the axes.

  • show_label_boxes (bool) – Whether node labels should be drawn with a bbox.

  • label_box_alpha (float) – Alpha for label boxes.

  • curved_edges (bool) – Whether to draw curved edges.

  • curve_radius (float) – Radius used when curved edges are enabled.

  • scale_edge_width_by_stoich (bool) – Whether edge widths should scale by stoichiometry.

  • stoich_width_factor (float) – Increment added per stoichiometric unit above 1.

  • linewidths (float) – Line width for normal node outlines.

  • highlight_linewidths (float) – Line width for highlighted node outlines.

  • edge_alpha (float) – Alpha value for edges.

  • node_alpha (float) – Alpha value for nodes.

  • show_node_outline (bool) – Whether node outlines should be visible.

  • label_fontweight (str) – Font weight used for node labels.

  • auto_reduce_labels_when_dense (bool) – Whether to reduce label font size for dense graphs.

  • dense_node_threshold (int) – Node threshold for classifying a graph as dense.

  • dense_edge_threshold (int) – Edge threshold for classifying a graph as dense.

  • dense_font_size (int) – Reduced label font size used for dense graphs.

alpha: float = 0.98#
arrows: bool = True#
arrowsize: int = 12#
arrowstyle: str = '-|>'#
auto_reduce_labels_when_dense: bool = True#
curve_radius: float = 0.0#
curved_edges: bool = False#
dense_edge_threshold: int = 70#
dense_font_size: int = 7#
dense_node_threshold: int = 45#
edge_alpha: float = 0.9#
edge_width: float = 1.2#
figsize: Tuple[float, float] = (12.0, 7.0)#
font_size: int = 8#
highlight_edge_width: float = 2.1#
highlight_linewidths: float = 1.6#
label_box_alpha: float = 0.0#
label_fontweight: str = 'regular'#
linewidths: float = 1.0#
margins: float = 0.12#
node_alpha: float = 1.0#
other_style: str = 'solid'#
product_style: str = 'solid'#
reactant_style: str = 'dashed'#
rule_node_shape: str = 's'#
rule_node_size: int = 540#
scale_edge_width_by_stoich: bool = True#
show_label_boxes: bool = False#
show_node_outline: bool = True#
species_node_shape: str = 'o'#
species_node_size: int = 760#
stoich_width_factor: float = 0.4#
class synkit.CRN.Visualize.vis.CRNVis(graph: DiGraph, layout: str = 'auto', species_label: str = 'label', rule_label: str = 'label', show_species_labels: bool = True, show_rule_labels: bool = True, font_size: int | None = None, max_label_chars: int | None = 28, wrap_label_at: int | None = None, style: CRNStyle = <factory>, palette: ColorPalette | str = 'nature_journal', palette_overrides: dict[str, str] | None=None, rule_color_mode: str = 'palette', rule_color_attr: str | None = None, rule_cmap: str = 'Greys', species_color_mode: str = 'palette', species_color_attr: str | None = None, species_cmap: str = 'Greys', node_color_overrides: Hashable, str] | None=None, node_spacing: float = 1.35, layer_spacing: float = 2.5, orientation: str = 'vertical', seed: int = 0, strict: bool = True)[source]#

Bases: object

Visualization helper for chemical reaction networks.

Parameters:
  • graph (nx.DiGraph) – Directed CRN graph to visualize.

  • layout (str) – Layout name passed to compute_layout().

  • species_label (str) – Node attribute used for species labels.

  • rule_label (str) – Node attribute used for rule labels.

  • show_species_labels (bool) – Whether species labels should be shown.

  • show_rule_labels (bool) – Whether rule labels should be shown.

  • font_size (Optional[int]) – Optional label font size override.

  • max_label_chars (Optional[int]) – Optional maximum number of characters per label.

  • wrap_label_at (Optional[int]) – Optional wrapping width for labels.

  • style (CRNStyle) – Style configuration object.

  • palette (ColorPalette | str) – Palette instance or palette name.

  • palette_overrides (Optional[dict[str, str]]) – Optional keyword overrides applied to the palette.

  • rule_color_mode (str) – Rule coloring mode.

  • rule_color_attr (Optional[str]) – Node attribute used when rule coloring mode is "attribute".

  • rule_cmap (str) – Matplotlib colormap name used for rule categorical colors.

  • species_color_mode (str) – Species coloring mode.

  • species_color_attr (Optional[str]) – Node attribute used when species coloring mode is "attribute".

  • species_cmap (str) – Matplotlib colormap name used for species categorical colors.

  • node_color_overrides (Optional[Mapping[Hashable, str]]) – Explicit per-node color overrides.

  • node_spacing (float) – Spacing passed to supported layouts.

  • layer_spacing (float) – Layer spacing passed to supported layouts.

  • orientation (str) – Orientation passed to supported layouts.

  • seed (int) – Random seed passed to stochastic layouts.

  • strict (bool) – Whether graph validation should be strict.

dense_graph() bool[source]#

Return whether the graph should be treated as dense.

Returns:

True if the graph exceeds node or edge thresholds.

Return type:

bool

draw(ax: Any = None, *, title: str | None = None, show: bool = False, with_legend: bool = True, edge_label_mode: str = 'none', highlight_nodes: Iterable[Hashable] | None = None, highlight_edges: Iterable[Tuple[Hashable, Hashable]] | None = None, highlight_cycles: bool = False, hide_axis: bool = True, auto_align_dense: bool = False) tuple[Any, Any, dict[Hashable, tuple[float, float]]][source]#

Draw the CRN.

Parameters:
  • ax (Any) – Existing Matplotlib axes. If None, a new figure and axes are created.

  • title (Optional[str]) – Optional plot title.

  • show (bool) – Whether to call matplotlib.pyplot.show().

  • with_legend (bool) – Whether to draw the default legend.

  • edge_label_mode (str) – Edge label mode passed to edge_labels().

  • highlight_nodes (Optional[Iterable[Hashable]]) – Optional nodes to highlight.

  • highlight_edges (Optional[Iterable[Tuple[Hashable, Hashable]]]) – Optional edges to highlight.

  • highlight_cycles (bool) – Whether to highlight species-containing strongly connected components.

  • hide_axis (bool) – Whether to hide axes decoration.

  • auto_align_dense (bool) – Whether to temporarily switch to automatic layout for dense graphs.

Returns:

Figure, axes, and node positions.

Return type:

tuple[Any, Any, dict[Hashable, tuple[float, float]]]

edge_labels(*, mode: str = 'none') dict[tuple[Hashable, Hashable], str][source]#

Build edge labels for the current graph.

Parameters:

mode (str) – Labeling mode passed to build_edge_labels().

Returns:

Mapping from edge to rendered label text.

Return type:

dict[tuple[Hashable, Hashable], str]

font_size: int | None = None#
graph: DiGraph#
property is_dag: bool#

Return whether the graph is acyclic.

Returns:

True if the graph is a DAG, else False.

Return type:

bool

layer_spacing: float = 2.5#
layout: str = 'auto'#
max_label_chars: int | None = 28#
node_color_overrides: Mapping[Hashable, str] | None = None#
node_labels() dict[Hashable, str][source]#

Build node labels for the current graph.

Returns:

Mapping from node identifier to rendered label text.

Return type:

dict[Hashable, str]

node_spacing: float = 1.35#
orientation: str = 'vertical'#
palette: ColorPalette | str = 'nature_journal'#
palette_overrides: dict[str, str] | None = None#
positions() dict[Hashable, tuple[float, float]][source]#

Compute node positions for the current graph and layout settings.

Returns:

Mapping from node identifier to (x, y) coordinates.

Return type:

dict[Hashable, tuple[float, float]]

rule_cmap: str = 'Greys'#
rule_color_attr: str | None = None#
rule_color_mode: str = 'palette'#
rule_label: str = 'label'#
property rule_nodes: list[Hashable]#

Return validated rule nodes.

Returns:

Rule node identifiers.

Return type:

list[Hashable]

save(path: str | Path, *, dpi: int = 300, bbox_inches: str = 'tight', **draw_kwargs: Any) Path[source]#

Draw and save the CRN figure.

Parameters:
  • path (str | Path) – Output file path.

  • dpi (int) – Figure DPI.

  • bbox_inches (str) – Bounding box mode passed to savefig.

  • draw_kwargs (Any) – Additional keyword arguments passed to draw().

Returns:

Saved output path.

Return type:

Path

seed: int = 0#
show_rule_labels: bool = True#
show_species_labels: bool = True#
species_cmap: str = 'Greys'#
species_color_attr: str | None = None#
species_color_mode: str = 'palette'#
species_label: str = 'label'#
property species_nodes: list[Hashable]#

Return validated species nodes.

Returns:

Species node identifiers.

Return type:

list[Hashable]

strict: bool = True#
strongly_connected_species() list[set[Hashable]][source]#

Return strongly connected components containing at least one species node.

Returns:

Species-containing strongly connected components.

Return type:

list[set[Hashable]]

style: CRNStyle#
subgraph(nodes: Iterable[Hashable]) CRNVis[source]#

Return a new CRNVis instance restricted to the given nodes.

Parameters:

nodes (Iterable[Hashable]) – Nodes to keep in the induced subgraph.

Returns:

New visualization helper for the induced subgraph.

Return type:

CRNVis

wrap_label_at: int | None = None#
synkit.CRN.Visualize.vis.draw_crn(graph: DiGraph, **kwargs: Any) tuple[Any, Any, dict[Hashable, tuple[float, float]]][source]#

Convenience wrapper around CRNVis.

Parameters:
  • graph (nx.DiGraph) – Directed CRN graph to visualize.

  • kwargs (Any) – Keyword arguments forwarded to CRNVis.

Returns:

Figure, axes, and node positions.

Return type:

tuple[Any, Any, dict[Hashable, tuple[float, float]]]