molfoundry.Rule#

class molfoundry.Rule#
static fromGMLString(gml, name=None, invert=False, add=True)#
Parameters:
Return type:

Rule

static fromDFS(dfs, name=None, labelType=LabelType.String, invert=False, add=True)#

Build a Rule from a RuleDFS line-notation string (L >> R).

Vertices are related across >> by their ids: a shared id whose label is unchanged is a context vertex, otherwise a relabeling. Pass labelType=LabelType.Term when the _-prefixed / * labels are term variables. Implicit hydrogens are not added on rule sides.

Parameters:
Return type:

Rule

static fromGMLFile(f, name=None, invert=False, add=True)#
Parameters:
Return type:

Rule

static identity(graph, name=None, *, constraints=(), condition=None, labelType=LabelType.String, add=True)#

The identity rule G <- G -> G on graph.

Everything is context, so the rule rewrites nothing. As an observable it counts the matches of graph in a state that satisfy constraints and condition (the pattern observables of Behr, Krivine, Andersen and Merkle, arXiv:2106.02573). It is the sqpoJumpClosure() of every rule whose input is graph under these conditions.

Rule vertices take the graph’s external ids – the ids of the GML it was read from (vertex.externalId) – when every vertex has a distinct one, and the vertex ids otherwise. constraints (any of AdjacencyConstraint, LabelAnyConstraint, ShortestPathConstraint and NoEdgeConstraint) and the nested condition name vertices by these ids, as the rule’s GML would; they are what matchConstraintsAdjacency and friends and matchCondition read back. A NoEdgeConstraint’s implied flag is ignored, since the rule creates no edge. name defaults to the graph’s name with a suffix. Like the other constructors, the rule is added to the global rule list unless add=False.

path = Graph.fromGMLString(
    'graph [ node [ id 0 label "C" ] node [ id 1 label "O" ] node [ id 2 label "C" ] '
    'edge [ source 0 target 1 label "-" ] edge [ source 1 target 2 label "-" ] ]',
    add=False)
# C-O-C whose carbons are not bonded to each other.
ether = Rule.identity(path, "ether", constraints=[NoEdgeConstraint(0, 2)], add=False)
ether.numMatches([state], ApplyMode.UseAny)

Raises LogicError when a constraint or the condition names a vertex the graph does not have.

Parameters:
Return type:

Rule

static fromMolFoundry(id, name=None, invert=False, add=True)#
Parameters:
Return type:

Rule

getGMLString(withCoords=False)#
Parameters:

withCoords (bool)

Return type:

str

makeInverse()#
Return type:

Rule

optimize()#

Return a folded copy of this rule.

Every node and edge that is present and unchanged on both sides (same label, and same stereo for nodes) is moved into the context (K) instead of appearing separately in the left (L) and right (R) sides. This rule itself is left unchanged and the returned rule carries the folded form; both have the same canonKey, which is computed on the folded form.

Return type:

Rule

compileConditions()#

Return a copy of this rule with its match constraints moved into its condition tree as expanded patterns.

Each matchConstraints* entry that has an exact pattern form becomes that pattern in matchCondition (a no-edge constraint becomes not exists the edge; an adjacency constraint becomes exists / not exists the required neighbors; a bounded shortest path becomes path patterns), never an opaque leaf. Opaque leaves the condition tree already carries are expanded the same way, in place. The converted constraints are conjoined with the condition the rule already has: appended to its children when its root is already an and, otherwise placed beside it under a new and root.

Each expansion is simplified: parts the rule’s own pattern already guarantees drop out (an “at least one O neighbor” the left side’s own bond provides, a path the left side already contains), and a constraint the pattern guarantees outright is removed without adding anything. Each remaining constraint stays one operand of the root and.

Kept as constraints, unchanged: those with no finite pattern form (label-any constraints, shortest-path lower bounds, adjacency constraints under term labels), and the no-edge constraints a loaded rule implies for each edge it creates (marked implied), which loading re-derives anyway. A tree leaf with no pattern form stays where it is in the tree. The result can still be inverted with makeInverse() whenever this rule can.

The returned rule admits exactly the same matches; it is decided by the generic pattern evaluator rather than the constraints’ tuned evaluators, which is slower on large graphs. This rule itself is left unchanged.

Return type:

Rule

dpoJumpClosure(name=None)#

The DPO jump closure I <- K -> I of this rule L <- K -> R.

As an observable it counts this rule’s DPO applications to a state: the matches of its input I = L that satisfy the rule’s application conditions and the dangling condition (Behr, Krivine, Andersen and Merkle, arXiv:2106.02573, Thm. 6(2) and Remark 3). What the rule deletes or relabels is deleted and recreated with its left label. Each deleted vertex is recreated under a fresh id, since one id on both sides is one kept vertex. name defaults to this rule’s name with a suffix.

Parameters:

name (str | None)

Return type:

Rule

sqpoJumpClosure(name=None)#

The SqPO jump closure I <- I -> I of this rule L <- K -> R.

As an observable it counts the matches of the input I = L that satisfy the rule’s application conditions; SqPO has no dangling condition. name defaults to this rule’s name with a suffix.

Parameters:

name (str | None)

Return type:

Rule

property id: int#
property molFoundryId: str | None#
property type: GraphType#
property name: str#
property labelType: LabelType#
property canonKey: str#
property numVertices: int#

The number of vertices in the rule’s span.

property numEdges: int#

The number of edges in the rule’s span.

property vertices: List[RuleVertex]#

The vertices of the rule’s span, each a RuleVertex.

Every vertex carries its left/right images and a Membership saying whether the rule keeps, changes, creates, or deletes it.

property edges: List[RuleEdge]#

The edges of the rule’s span, each a RuleEdge.

Each edge’s endpoints are RuleVertex objects, so an edge’s span information reaches its endpoints’ via edge.source / edge.target.

getVertex(id)#

The span vertex with the given rule node id, or None if absent.

Parameters:

id (int)

Return type:

RuleVertex | None

getEdge(source, target)#

The span edge between source and target (either order), or None.

Parameters:
Return type:

RuleEdge | None

property matchConstraintsAdjacency: Tuple[AdjacencyConstraint, ...]#

The rule’s adjacency constraints (GML constrainAdj), read-only.

property matchConstraintsLabelAny: Tuple[LabelAnyConstraint, ...]#

The rule’s label constraints (GML constrainLabelAny), read-only.

property matchConstraintsShortestPath: Tuple[ShortestPathConstraint, ...]#

The rule’s shortest-path constraints (GML constrainShortestPath), read-only.

property matchConstraintsNoEdge: Tuple[NoEdgeConstraint, ...]#

The rule’s no-edge constraints (GML constrainNoEdge), read-only.

Includes the ones loading a rule adds for every edge it creates, marked implied.

property matchCondition: ConditionTrue | ConditionExists | ConditionNot | ConditionAnd | ConditionOr | AdjacencyConstraint | LabelAnyConstraint | ShortestPathConstraint | NoEdgeConstraint | None#

The rule’s nested application condition (GML condition), read-only, or None when it has none. Vertices are named by id, as in GML; see molfoundry.constraints. A match must satisfy it in addition to the matchConstraints*.

property numLeftComponents: int#
property numRightComponents: int#
numMatches(graphs, mode=ApplyMode.UseAll, labelSettings=LabelSettings(LabelType.String, LabelRelation.Isomorphism), *, onlyProper=None)#

The number of matches DG.build().apply(graphs, rule, mode) admits.

mode selects which graphs a match may use, as in DG.Builder.apply() (see ApplyMode). For a rule with two isolated A vertices and chains A-A-A-A:

  • ApplyMode.UseAll (default) counts the matches that use every listed graph exactly once: numMatches([chain]) is 12, the ordered pairs inside the chain, and numMatches([chain, chain]) is 32, only the 2 * 16 pairs between the chains use both;

  • ApplyMode.UseAny counts every match in exactly the listed graphs: numMatches([chain, chain], ApplyMode.UseAny) is 56, 2 * 12 inside the chains and 2 * 16 between them;

  • ApplyMode.UseAnyMultiplicity lets a match span further copies: numMatches([chain], ApplyMode.UseAnyMultiplicity) is 44, 12 inside one copy and 2 * 16 across two.

Matching, the dangling condition, the rule’s application conditions, and the checks of the rewrite itself (an edge the rule creates must not exist yet) run as in a derivation, but no products are built, canonicalized, or added to a derivation graph. Every match counts: matches related by a symmetry of the graphs and both orientations of a symmetric rule are counted separately, and so are matches that differ only in which copy of a graph plays which role. That makes this the sum of DG.HyperEdge.numMatches() over the hyperedges apply derives, except that under UseAny a match using one of several identical listed graphs counts once per graph it could use, which a hyperedge (one per reaction) does not tell apart. labelSettings defaults to that of a DG. MØD’s onlyProper flag is still accepted: true is UseAll, false UseAny.

A rule with an empty left side has one match, the empty one, the only map of the empty graph into a state. It uses no graph, so UseAny and UseAnyMultiplicity admit it in every state and UseAll only when graphs is empty; the rule’s conditions are read on the empty host it uses. The identity rule of the empty graph thus counts the constant 1, and a rule creating something from nothing one application per state, as apply derives it: a hyperedge without sources.

Parameters:
Return type:

int

matches(graphs, mode=ApplyMode.UseAll, labelSettings=LabelSettings(LabelType.String, LabelRelation.Isomorphism))#

The matches numMatches() counts, each as the match DG.Builder.applyMatch() takes to apply the rule there.

A match maps every vertex of the left side, by rule vertex id, to (graph index, vertex id): the position of its graph in graphs and the vertex’s id in that graph. mode is ApplyMode.UseAll (default) or ApplyMode.UseAny, both reading graphs as the concrete state, each listed graph one copy; identical graphs listed twice are two copies, told apart by their positions. ApplyMode.UseAnyMultiplicity raises a LogicError, as its matches may use copies graphs does not list. For a rule with two isolated A vertices and a chain A-A-A-A, matches([chain, chain], ApplyMode.UseAny) lists 56 matches: 12 inside each chain and 32 between them, the latter being all matches([chain, chain]) lists.

for match in rule.matches([ethanol], ApplyMode.UseAny):
    edge, vertexMap = builder.applyMatch([ethanol], rule, match)

The matches pass every check numMatches() makes, in a fixed order. A rule with an empty left side lists the empty match, {}, where numMatches() counts it. labelSettings defaults to that of a DG.

Parameters:
Return type:

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

print() → None#
print(printer: GraphPrinter | None = None) → None
Parameters:

printer (GraphPrinter | None)

Return type:

None

svg() → str#
svg(printer: GraphPrinter | None = None) → str

Render the rule to an SVG string and return it — the same depiction print shows, without the summary card wrapper.

Parameters:

printer (GraphPrinter | None)

Return type:

str