cottax.core.driven

How a problem is answered, before anything runs it: drivers, driven nodes, their ops.

Dependency:

driver (the contract: DriverContract, Role / PerUnknown / PerProblem, arity;

entry_for, a table’s entry for a contract’s most specific class)

||——— / /

nodes roles (nodes: DrivenNode, the level; Driven, its final; condition_of;

|| role_slots, where each problem takes or reports a role, by unknown; || roles: Start / Steps, the places the shipped contracts take) ||——— / /

ops proof (ops: Assign / Undrive; AssignByRule, an Assign at the places

a rule gives; proof: DrivenGraph, every problem driven – what an export reads)

class DriverContract[V: Place][source]

Bases: Frozen, Generic[V]

Algorithm answering a ConditionalNode’s problem.

takes (input roles) is not exhaustive: certain choices can not be made from the graph such as a Linear Solver type for a Newton driver.

accepts: AbstractVar[Callable[[ConditionalNode[V]], bool]]

Whether it accepts that ConditionalNode

takes: AbstractVar[tuple[type[Role], ...]]

Input roles

reports: AbstractVar[tuple[type[Role], ...]]

Output roles.

class PerProblem[source]

Bases: Role

Role about solve (e.g. global tolerance)

classmethod arity(node: ConditionalNode)[source]

How many places the role takes on node.

Return type:

int

class PerUnknown[source]

Bases: Role

Role per unknown (e.g. initial guesses)

classmethod arity(node: ConditionalNode)[source]

How many places the role takes on node.

Return type:

int

class Role[source]

Bases: ABC

What a place is to a driver: a class, never a value. Free to extend.

abstractmethod classmethod arity(node: ConditionalNode)[source]

How many places the role takes on node.

Return type:

int

entry_for[T, D](table: Mapping[type[DriverContract], T], contract: DriverContract, default: D = None)[source]

The entry of table for contract’s most specific class along its ancestry, whatever order the table is written in; default if none covers it.

Return type:

Union[T, D]

class DrivenNode[V: Place][source]

Bases: ConditionalNode[V], Generic[V]

A conditional node with a driver answering it. Abstract like FunctionalNode & ConditionalNode; so an implementation or no implementation is possible.

condition: AbstractVar[ConditionalNode[V]]

The node answered, without the driver.

contract: AbstractVar[DriverContract[V]]

abstract to ABC until a subclass binds the name, and absent on a class that declares it as a field.

Type:

What the level binds in place of the annotation

data: AbstractVar[tuple[tuple[V, ...], ...]]

One slot per role in driver.takes, each as many places as its role’s arity.

reports: AbstractVar[tuple[tuple[V, ...], ...]]

One slot per role in driver.reports, the same way.

abstractmethod undriven()[source]

The condition node with the driver taken off: what Undrive edits. A final that cannot have it taken off refuses here.

Return type:

ConditionalNode[V]

data_of(role: type)[source]

The places its driver takes role at, the slot read off the node: one per unknown for a per-unknown role, one for a per-problem one; None where the driver takes no such role.

Return type:

tuple[V, ...] | None

places_of(role: type)[source]

The places its driver takes or reports role at, laid out as data_of; None where it has no such role.

Return type:

tuple[V, ...] | None

class Driven[V: Place](condition: ConditionalNode[V], contract: DriverContract[V], data: tuple[tuple[V, ...], ...], reports: tuple[tuple[V, ...], ...])[source]

Bases: DrivenNode[V], Generic[V]

Final of DrivenNode that has no implementation.

condition: ConditionalNode[V]

The node answered, without the driver.

contract: DriverContract[V]
data: tuple[tuple[V, ...], ...]

One slot per role in driver.takes, each as many places as its role’s arity.

reports: tuple[tuple[V, ...], ...]

One slot per role in driver.reports, the same way.

checks: PerLevel[tuple[Callable[[Any], object], ...]] = (<function check_pairing>, <function check_slots>)

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

property unknowns: tuple[V, ...]

abstract to ABC until a subclass binds the name, and absent on a class that declares it as a field.

Type:

What the level binds in place of the annotation

property conditions: tuple[V, ...]

abstract to ABC until a subclass binds the name, and absent on a class that declares it as a field.

Type:

What the level binds in place of the annotation

property reads: tuple[V, ...]

abstract to ABC until a subclass binds the name, and absent on a class that declares it as a field.

Type:

What the level binds in place of the annotation

property owns: tuple[V, ...]

abstract to ABC until a subclass binds the name, and absent on a class that declares it as a field.

Type:

What the level binds in place of the annotation

determined(unknowns: tuple[V, ...])[source]

Refused: an algorithm was chosen for the node as it stands, and its per-unknown slots are laid out against the unknowns it had.

Return type:

Driven[V]

undriven()[source]

The condition node with the driver taken off: what Undrive edits. A final that cannot have it taken off refuses here.

Return type:

ConditionalNode[V]

relabel(renaming: Renaming[V])[source]

The same definition with its places renamed.

Return type:

Driven[V]

is_driven(d: object)[source]

A node carrying a driver, bare or under what runs it.

Return type:

bool

condition_of(node: Any)[source]

A driven node’s condition, else the node itself.

Return type:

Any

role_slots[N: Label, V: Place](graph: NestingGraph[N, V], role: type[Role])[source]

Each place a driven problem takes or reports role at, in binding order: the place, its problem, and for a per-unknown role the unknown it pairs with (None for a per-problem one). A place two problems take is there twice.

Return type:

tuple[tuple[V, N, Optional[V]], ...]

class Assign[N: Label, V: Place](problem: N, contract: DriverContract[V], data: tuple[tuple[V, ...], ...], reports: tuple[tuple[V, ...], ...])[source]

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

Attach a driver to a condition node, and say where each of its roles sits: the algorithm choice and its places, recorded in the plan and carried by the node. Where a place sits is a decision, so the op records it: a surface supplies the obvious ones.

problem: N
contract: DriverContract[V]
data: tuple[tuple[V, ...], ...]
reports: tuple[tuple[V, ...], ...]
checks_graph: PerLevel[tuple[Callable, ...]] = (<function check_drivable>,)

(op, graph) -> Iterator[Violation], collected by refusals and raised by apply.

Type:

What the op needs of the graph before it can compute anything

redefined(graph: NestingGraph[N, V])[source]

The new definition for each node this touches. Names not here are untouched.

Return type:

Mapping[N, NodeDefinition[V]]

class AssignByRule[N: Label, V: Place](problem: N, contract: DriverContract[V], places: Callable[..., tuple[tuple[tuple[V, ...], ...], tuple[tuple[V, ...], ...]]])[source]

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

Assign at the places places(problem, unknowns, contract) gives, the problem’s unknowns read when it is applied: the rule is recorded, so a changed model has its places derived again.

problem: N
contract: DriverContract[V]
places: Callable[..., tuple[tuple[tuple[V, ...], ...], tuple[tuple[V, ...], ...]]]
checks_graph: PerLevel[tuple[Callable, ...]] = (<function check_assignable>,)

(op, graph) -> Iterator[Violation], collected by refusals and raised by apply.

Type:

What the op needs of the graph before it can compute anything

composed(graph: NestingGraph[N, V])[source]

The ops this one is. Takes a graph, so an expansion may depend on what it meets.

Return type:

tuple[Assign[N, V]]

class Undrive[N: Label, V: Place](problem: N)[source]

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

The inverse of Assign: the condition node alone again, and the driver’s places gone with it – undriven, asked of the node, so a wrapper refuses for itself.

problem: N
checks_graph: PerLevel[tuple[Callable, ...]] = (<function check_undrives_a_driven_node>,)

(op, graph) -> Iterator[Violation], collected by refusals and raised by apply.

Type:

What the op needs of the graph before it can compute anything

redefined(graph: NestingGraph[N, V])[source]

The new definition for each node this touches. Names not here are untouched.

Return type:

Mapping[N, NodeDefinition[V]]

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

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

Executable graph with additionally all problems driven.

checks_node: PerLevel[tuple[Callable[[N, NodeDefinition[V]], Iterator[Violation]], ...]] = (<function check_driven>,)

the one thing a level below adds.

Type:

(name, node) -> violations

class Start[source]

Bases: PerUnknown

Where each unknown starts.

class Steps[source]

Bases: PerProblem

Reported: how many iterations the solve took.

Submodules