cottax.core.maths.nesting module

Nesting graph: Graph + nesting forest

check_nesting_ends_bound(g: NestingGraph)[source]

Check the within edge has both nodes in the graph.

W ⊆ N × N

Return type:

Iterator[Violation]

check_nesting_ends_are_problems(g: NestingGraph)[source]

Nesting can only be between problems.

W ⊆ N_P × N_P

Return type:

Iterator[Violation]

check_no_nesting_loops(g: NestingGraph)[source]

Nesting can not be looped: this would imply nesting within itself in some form.

(N_P, W) is a forest

Only the acyclicity is checked here: within is a mapping, so one outer per inner ((n,m), (n,m’) ∊ W ⟹ m = m’) holds by construction, and acyclic with out-degree at most one is a forest.

Return type:

Iterator[Violation]

check_nesting_ends_on_one_cycle(g: NestingGraph)[source]

Both ends of a nesting are on one cycle: the inner lies in the outer’s cycle. The inner’s output is required for the outer’s inputs and vice-versa – otherwise the inner does not depend on the outer’s iterate, or the outer never reads its answer, and it could run outside.

p ~ q in N A(q) ∀ (p, q) ∊ W i.e. p ∊ S_q, the cycle of q

A pair with an end unbound or not a problem is skipped: those are other rules’.

Return type:

Iterator[Violation]

check_blocks_partition(g: NestingGraph, blocks: Iterable[Iterable])[source]

Each block is at least two nodes, and no node is in two.

Return type:

Iterator[Violation]

check_blocks_own_something(g: NestingGraph, blocks: Iterable[Iterable])[source]

A block contracts into a computation, so it owns something.

Return type:

Iterator[Violation]

class NestingGraph[N: Label, V: Place](graph: AbstractGraph[N, V], within: OrderedMap[N, N])[source]

Bases: Frozen, Generic[N, V]

A graph plus nesting decision: within, inner -> outer

graph: AbstractGraph[N, V]
within: OrderedMap[N, N]
checks: PerLevel[tuple[Callable[[Any], object], ...]] = (<function check_nesting_ends_bound>, <function check_no_nesting_loops>, <function check_nesting_ends_are_problems>, <function check_nesting_ends_on_one_cycle>)

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

property definitions: Mapping[N, NodeDefinition[V]]
property nodes: tuple[N, ...]
property problems: tuple[N, ...]

the ends a nesting pair may have.

Type:

The problems, in binding order

property outermost_problems: tuple[N, ...]

Problems that are not nested in any other

enclosing(problem: N)[source]

The problems problem is nested in transitively: A(q), every problem with a path from q in (N_P, W).

Return type:

tuple[N, ...]

cycle_of(problem: N)[source]

The cycle problem is on, and itself: its strongly connected component in the graph with the problems enclosing it taken out, in binding order.

S_p = {k ∊ N A(p) : k ~ p in N A(p)} (~ in the induced subgraph, not in G)

Return type:

tuple[N, ...]

interior(problem: N)[source]

What one iteration of problem runs: its cycle with it taken out.

Return type:

Self

subgraph(keep: Iterable[N])[source]

Keep only those nodes in keep, with their definitions and the edges among them, dropping pairs with one end not kept.

Return type:

Self

contract(blocks: tuple[tuple[N, ...], ...])[source]

Each block of at least two nodes contracted into one Function at its first member’s place: reading what the block reads from outside, owning what it owns. Every pair with an end in a block is dropped, since a box is no problem. A pair outside keeps its cycle, since a contraction only adds paths, so nothing is re-asked.

Return type:

Self

class ProvedGraph[N: Label, V: Place](graph: NestingGraph[N, V])[source]

Bases: Frozen, Generic[N, V]

Wraps a nesting graph and forwards the methods. Additional checks can be put on here.

graph: NestingGraph[N, V]
property definitions: Mapping[N, NodeDefinition[V]]
property nodes: tuple[N, ...]
property within: Mapping[N, N]
property problems: tuple[N, ...]
property outermost_problems: tuple[N, ...]
enclosing(problem: N)[source]
Return type:

tuple[N, ...]

cycle_of(problem: N)[source]
Return type:

tuple[N, ...]

interior(problem: N)[source]
Return type:

NestingGraph[N, V]

subgraph(keep: Iterable[N])[source]
Return type:

NestingGraph[N, V]

class Unbound(inner: Label, outer: Label)[source]

Bases: Violation

inner: Label
outer: Label
template: AbstractClassVar[str] = 'nesting {inner!r} in {outer!r}: an end is not a node of this graph'

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

Type:

Wording

class NotAProblem(nodes: tuple[Label, ...])[source]

Bases: Violation

nodes: tuple[Label, ...]
template: AbstractClassVar[str] = '{nodes} determines nothing, so no iteration of it answers anything -- an end of a nesting is a problem: `Determine` it, naming the unknowns it fixes, or `Unnest` it first so the plan says the nesting went'

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

Type:

Wording

class Unreachable(inner: Label, outer: Label)[source]

Bases: Violation

inner: Label
outer: Label
template: AbstractClassVar[str] = '{inner!r} and {outer!r} are not on one cycle, so no iteration of the one re-runs the other and there is nothing for the nesting to mean -- `Unnest` it before cutting or rewiring the pair apart'

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

Type:

Wording

class SelfNested(inner: Label)[source]

Bases: Violation

inner: Label
template: AbstractClassVar[str] = '{inner!r} inside itself -- an iteration does not answer the problem it is'

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

Type:

Wording

class NestingLoop(inner: Label, outer: Label, chain: tuple[Label, ...])[source]

Bases: Violation

inner: Label
outer: Label
chain: tuple[Label, ...]
template: AbstractClassVar[str] = '{outer!r} is already answered inside {inner!r} ({chain}), so nesting the one in the other closes a loop -- nesting is a forest'

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

Type:

Wording

class BlockTooSmall(block: tuple[Label, ...])[source]

Bases: Violation

block: tuple[Label, ...]
template: AbstractClassVar[str] = 'block {block} is not two nodes -- a box contracts at least two into one'

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

Type:

Wording

class NodeInTwoBlocks(nodes: tuple[Label, ...])[source]

Bases: Violation

nodes: tuple[Label, ...]
template: AbstractClassVar[str] = '{nodes} each in two blocks -- a node is contracted into one box at most'

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

Type:

Wording

class BoxOwnsNothing(block: tuple[Label, ...])[source]

Bases: Violation

block: tuple[Label, ...]
template: AbstractClassVar[str] = 'block {block} owns nothing, so as one node it would compute nothing and be unreachable -- a box is a computation, so contract only what produces'

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

Type:

Wording