cottax.core.maths.cut_rules module

Rules on how to cut a graph’s couplings.

type ToCut[N: Label, V: Place] = Mapping[V, tuple[N, ...]]

One closure’s worth: which variables are cut, for which readers.

class CutRule[N: Label, V: Place][source]

Bases: Frozen, Generic[N, V]

What to cut in the graph handed: the coupling of its function nodes, one group per closure.

abstractmethod to_cuts(graph: AbstractGraph[N, V])[source]

One group per closure.

Return type:

tuple[ToCut[N, V], ...]

type Opened[N: Label, V: Place] = tuple[tuple[N, ...], tuple[ToCut, ...]]

One cycle opened: its members in binding order, and the groups the rule cut it into.

cuts_per_cycle[N: Label, V: Place](graph: NestingGraph[N, V], rule: CutRule[N, V])[source]

The rule asked of each functional cycle: the condition nodes dropped, and each cyclic component of what is left handed to the rule, alone. Per cycle, its members and its groups.

Return type:

tuple[Opened[N, V], ...]

per_functional_cycle[N: Label, V: Place](graph: NestingGraph[N, V], rule: CutRule[N, V])[source]

cuts_per_cycle’s groups, every cycle’s in a row.

Return type:

tuple[ToCut[N, V], ...]

coupling_reads[N: Label, V: Place](graph: AbstractGraph[N, V])[source]

Every read of every variable owned in the graph handed, holding nothing back.

Return type:

ToCut[N, V]

gauss_seidel[N: Label, V: Place](graph: AbstractGraph[N, V], order: Sequence[N])[source]

coupling_reads with every reader that follows its owner in order dropped: only the back edges are opened.

Return type:

ToCut[N, V]

minimal_feedback_order[N: Label, V: Place](graph: AbstractGraph[N, V], limit: int)[source]

The order of graph’s nodes a Gauss-Seidel sweep opens the fewest variables in. Exact: a DP over subsets, a node’s cost after a set being how many of its couplings that set reads. Ties fall to binding order.

Return type:

tuple[N, ...]

check_keys_distinct(rule: ByName)[source]

No node keys two rules: which one applies would be the order written.

Return type:

Iterator[Violation]

class ByName[N: Label, V: Place](rules: tuple[tuple[N, CutRule[N, V]], ...])[source]

Bases: CutRule[N, V], Generic[N, V]

A rule per cycle, keyed by a node on it. Cycles are disjoint, so exactly one key lies on the graph handed; none or several is refused, never the first taken.

rules: tuple[tuple[N, CutRule[N, V]], ...]
checks: PerLevel[tuple[Callable[[Any], object], ...]] = (<function check_keys_distinct>,)

Callable [self] -> iterable of violations, which are raised at construction unless skipped (see unchecked).

to_cuts(graph: AbstractGraph[N, V])[source]

One group per closure.

Return type:

tuple[ToCut[N, V], ...]

class NoCuts[N: Label, V: Place][source]

Bases: CutRule[N, V], Generic[N, V]

Nothing opened, said rather than fallen into.

to_cuts(graph: AbstractGraph[N, V])[source]

One group per closure.

Return type:

tuple[ToCut[N, V], ...]

class Jacobi[N: Label, V: Place][source]

Bases: CutRule[N, V], Generic[N, V]

Every coupling, for every reader, in one closure: each node runs from the previous iterate alone.

to_cuts(graph: AbstractGraph[N, V])[source]

One group per closure.

Return type:

tuple[ToCut[N, V], ...]

class Sweep[N: Label, V: Place][source]

Bases: CutRule[N, V], Generic[N, V]

A Gauss-Seidel sweep: the back edges of an order only, in one closure, since a forward edge keeps this sweep’s value.

abstractmethod order_of(graph: AbstractGraph[N, V])[source]

The order this graph is swept in, naming its nodes exactly once each.

Return type:

tuple[N, ...]

to_cuts(graph: AbstractGraph[N, V])[source]

One group per closure.

Return type:

tuple[ToCut[N, V], ...]

class GaussSeidel[N: Label, V: Place][source]

Bases: Sweep[N, V], Generic[N, V]

In binding order.

order_of(graph: AbstractGraph[N, V])[source]

The order this graph is swept in, naming its nodes exactly once each.

Return type:

tuple[N, ...]

class GaussSeidelMinimal[N: Label, V: Place](limit: int)[source]

Bases: Sweep[N, V], Generic[N, V]

In the order minimal_feedback_order finds: the fewest variables opened.

limit: int

Above this many nodes on one cycle the exact search (2^n n) is refused.

order_of(graph: AbstractGraph[N, V])[source]

The order this graph is swept in, naming its nodes exactly once each.

Return type:

tuple[N, ...]

class GaussSeidelOrdered[N: Label, V: Place](order: tuple[N, ...])[source]

Bases: Sweep[N, V], Generic[N, V]

In the order written, which names the graph’s nodes exactly once each or is refused: an order meant for one cycle and got wrong is what leaves it unswept.

order: tuple[N, ...]
order_of(graph: AbstractGraph[N, V])[source]

The order this graph is swept in, naming its nodes exactly once each.

Return type:

tuple[N, ...]

class OrderMismatch(order: tuple, nodes: tuple)[source]

Bases: Violation

order: tuple
nodes: tuple
template: AbstractClassVar[str] = 'gauss_seidel: the order {order!r} does not name the nodes {nodes!r} exactly once each -- an order sweeps one cycle, and one per cycle is `ByName`'

e.g. ‘output {place!r} is owned by both {other!r} and {node!r}’

Type:

Wording

class CycleTooLarge(size: int, limit: int)[source]

Bases: Violation

size: int
limit: int
template: AbstractClassVar[str] = '{size} nodes on one cycle is beyond the exact order search (limit {limit}): raise `GaussSeidelMinimal(limit=)`, or hand `GaussSeidelOrdered` an order'

e.g. ‘output {place!r} is owned by both {other!r} and {node!r}’

Type:

Wording

class KeyRepeats(keys: tuple)[source]

Bases: Violation

keys: tuple
template: AbstractClassVar[str] = 'by_name: {keys!r} each key more than one rule'

e.g. ‘output {place!r} is owned by both {other!r} and {node!r}’

Type:

Wording

class NoRule(nodes: tuple)[source]

Bases: Violation

nodes: tuple
template: AbstractClassVar[str] = 'no rule keyed by a node of {nodes!r}: key one, `NoCuts()` to leave it alone, or use the one rule alone for every cycle'

e.g. ‘output {place!r} is owned by both {other!r} and {node!r}’

Type:

Wording

class SeveralRules(keyed: tuple)[source]

Bases: Violation

keyed: tuple
template: AbstractClassVar[str] = 'several rules keyed on one cycle, by {keyed!r}: cycles are disjoint, so one key lies on one'

e.g. ‘output {place!r} is owned by both {other!r} and {node!r}’

Type:

Wording