cottax.consumers.architectures.architectures module

MDAO architectures as one op each, over the cut rules and a Closing handed in:

Plan(g) + MDF(GaussSeidel(), cx.closing, opt) + Assign(…) Plan(g) + MDA(GaussSeidel(), cx.closing) # no optimiser: an analysis Plan(g) + CloseFunctionalCycles(GaussSeidel(), cx.closing) # a bare cut, no architecture

not_implicit[N: Label](graph: NestingGraph[N, Any], problem: N)[source]

Why the problem is not an implicit model, by its ModelReading; refused if none.

Return type:

tuple[Violation, ...]

body_of_problem[N: Label](graph: NestingGraph[N, Any], problem: N)[source]

The function nodes that are the problem’s own, by its ModelReading.

Return type:

tuple[N, ...]

combines_as(node: Any)[source]

The kind node folds as, None where it folds into nothing or nobody answers.

Return type:

type | None

lies_inside[N: Label](graph: NestingGraph[N, Any], inner: N, outer: N, bodies: dict[N, tuple[N, ...]])[source]

inner and its whole body on outer’s cycle, and its body part of outer’s, which holds more: it can be placed nowhere but inside outer.

Return type:

bool

inside[N: Label](graph: NestingGraph[N, Any], bodies: dict[N, tuple[N, ...]])[source]

Each problem lying wholly inside another’s body, and the least such other, the one it is nested in; in binding order. The pairs are a forest, a body growing up each chain.

Return type:

OrderedMap[N, N]

chain[N: Label](pairs: OrderedMap[N, N], p: N)[source]

p and every problem it lies inside (inside’s pairs), inner to outer.

Return type:

tuple[N, ...]

shared_bodies[N: Label](graph: NestingGraph[N, Any], bodies: dict[N, tuple[N, ...]])[source]

Two problems sharing a body node, neither inside the other at any depth.

Return type:

Iterator[Violation]

folded_as[N: Label](op: Architecture, graph: NestingGraph[N, Any], into: N, nodes: Sequence[N])[source]

The kind into combines as, every one of nodes combining as it; else refused.

Return type:

type

combined[N: Label](op: Architecture, graph: NestingGraph[N, Any], into: N, nodes: Sequence[N])[source]

nodes combined into into, their first, as folded_as says: one Combine, or none for one node.

Return type:

tuple[GraphOp, ...]

class OnCycle[N: Label](closures: tuple[N, ...], declared: tuple[N, ...])[source]

Bases: Frozen, Generic[N]

The problems on one cycle of the scope, as a final reads them.

closures: tuple[N, ...]

The ones the cutting bound, in binding order.

declared: tuple[N, ...]

The ones the model declared, but those nested inside another’s body, in binding order.

class Resolution[N: Label, V: Place](absorbed: tuple[GraphOp[N, V], ...], outside: tuple[GraphOp[N, V], ...], closures: tuple[GraphOp[N, V], ...], opened: NestingGraph[N, V], combining: tuple[GraphOp[N, V], ...], graph: NestingGraph[N, V])[source]

Bases: Frozen, Generic[N, V]

Architecture applied to a graph in terms of GraphOps and the intermediate graphs. Useful for extracting which closures were inserted.

absorbed: tuple[GraphOp[N, V], ...]

one Combine, or none.

Type:

The requirements the design reaches, combined into the top

outside: tuple[GraphOp[N, V], ...]

the analysis’s closures and placing.

Type:

What resolved the cycles off the scope’s

closures: tuple[GraphOp[N, V], ...]

what the Closing returned.

Type:

What the cutting bound, one closure per group

opened: NestingGraph[N, V]

The graph after those two and before any problem is placed.

combining: tuple[GraphOp[N, V], ...]

each lying inside another’s body nested there, then the final’s own, placing the closures and the declared problems.

Type:

The ops placing the problems

graph: NestingGraph[N, V]

The result.

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

Bases: Frozen, Generic[N, V]

Which problems of the graph handed are seen as one function each.

abstractmethod folded(graph: NestingGraph[N, V])[source]

The problems to fold, in binding order.

Return type:

tuple[N, ...]

check_nothing_nested(op: Architecture, graph: NestingGraph)[source]
Return type:

Iterator[Violation]

check_implicit_models(op: Architecture, graph: NestingGraph)[source]
  • An implicit model in its own language (ModelReading.not_implicit); where the final combines what is declared, combining as the top does

  • No two bodies share a node, unless one problem lies wholly inside the other’s body (inside), where it is nested

Asked of the graph without the design, nothing nested.

Return type:

Iterator[Violation]

class Architecture[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V])[source]

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

An MDAO architecture, with a top (Monolithic) or without (Coupled).

A StagedOp, since each stage is decided off the graph the one before leaves; like any composition it proves nothing of its own, every op it applies being checked.

  1. what the level absorbs is combined (absorbing), and every cycle then off the level’s own is resolved (outside);

  2. the cycles of the level’s scope are cut over the boxes the final names, and each group is closed with one problem, the closure;

  3. every problem lying wholly inside another’s body is nested there, at every depth (unless the final combines declared problems, which then combines it as any); then every problem on each cycle of the scope is placed as the final’s combining says, the closures apart from the problems the model declared.

rule: CutRule[N, V]

the MDA method.

Type:

What is cut on each cycle

closing: Closing[N, V]

the op, and where its problem binds.

Type:

How a group is closed

boxes: AbstractVar[Boxes[N, V]]

Which solves in the scope the rule sees as one function each.

design: AbstractVar[tuple[N, ...]]

the top, or none.

Type:

The problems that are the level’s own and not models

combines_declared: ClassVar[bool] = True

Whether the final may Combine a declared problem into another, so each must combine as the top does; a level that only nests them says False, and then takes a problem combining as nothing.

checks_graph: PerLevel[tuple[Callable, ...]] = (<function check_nothing_nested>, <function check_implicit_models>)

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

Type:

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

abstractmethod scope(graph: NestingGraph[N, V])[source]

The graph the cutting sees, and whose cycles are placed.

Return type:

NestingGraph[N, V]

abstractmethod outside(graph: NestingGraph[N, V])[source]

What resolves the cycles the scope leaves out, once absorbed.

Return type:

tuple[GraphOp[N, V], ...]

abstractmethod absorbing(graph: NestingGraph[N, V])[source]

What is combined before anything is cut.

Return type:

tuple[GraphOp[N, V], ...]

abstractmethod combining(opened: NestingGraph[N, V], closures: Sequence[N])[source]

The ops placing what lies in the scope, read off opened, the graph the cutting leaves; closures is the problems it bound.

Return type:

Sequence[GraphOp[N, V]]

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

Absorb; resolve what then lies outside; cut and close the scope of what is left; place every problem on its cycles, the closures being the problems the cutting bound.

Return type:

Generator[Sequence[GraphOp[N, V]], NestingGraph[N, V], None]

nesting_inside(scope: NestingGraph[N, V])[source]

Each problem of the scope lying wholly inside another’s body nested there, read before anything is cut; none where the final combines declared problems.

Return type:

tuple[GraphOp[N, V], ...]

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

The whole derivation: each stage’s ops and the graph it leaves. Refused as apply refuses.

Return type:

Resolution[N, V]

cycles_under(opened: NestingGraph[N, V], closures: Sequence[N])[source]

Per cycle of the scope in opened, the problems on it: the closures the cutting bound and the ones the model declared, but those already nested.

Return type:

tuple[OnCycle[N], ...]

check_top_bound(op: Monolithic, graph: NestingGraph)[source]
Return type:

Iterator[Violation]

check_top_is_problem(op: Monolithic, graph: NestingGraph)[source]
Return type:

Iterator[Violation]

check_top_combinable(op: Monolithic, graph: NestingGraph)[source]

The top is combined with what it absorbs and, by the final, with closures or declared problems: it combines as some kind, and what it absorbs as the same.

Return type:

Iterator[Violation]

reached_requirements[N: Label, V: Place](graph: NestingGraph[N, V], top: N)[source]

Every requirement whose conditions the design of top reaches.

Return type:

tuple[N, ...]

class Monolithic[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V], top: N, *, analysis: Optional[Analysis[N, V]] = None)[source]

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

Under a top: its interior is the scope, every requirement the design reaches is combined into it first, and every cycle then off the top’s is resolved by an analysis.

top: N

nothing searches for an optimiser.

Type:

The problem the design lives in. Required

analysis: Optional[Analysis[N, V]] = None

What resolves every cycle off the top’s; None is an MDA with this rule and closing.

checks_graph: PerLevel[tuple[Callable, ...]] = (<function check_top_bound>, <function check_top_is_problem>, <function check_top_combinable>)

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

Type:

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

property design: tuple[N, ...]

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

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

The graph the cutting sees, and whose cycles are placed.

Return type:

NestingGraph[N, V]

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

The analysis over the graph with the top’s cycle taken out, its ops applied to the whole: a cycle off the top’s is a component of its own.

Return type:

tuple[GraphOp[N, V], ...]

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

Every requirement whose conditions the design of top reaches, combined into top: one Combine, or nothing.

Return type:

tuple[GraphOp[N, V], ...]

class Coupled[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V])[source]

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

No top: the whole graph is the scope and nothing is absorbed. A requirement is left where it is, for the proof to refuse.

design: AbstractVar[tuple[N, ...]] = ()

the top, or none.

Type:

The problems that are the level’s own and not models

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

The graph the cutting sees, and whose cycles are placed.

Return type:

NestingGraph[N, V]

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

What resolves the cycles the scope leaves out, once absorbed.

Return type:

tuple[GraphOp[N, V], ...]

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

What is combined before anything is cut.

Return type:

tuple[GraphOp[N, V], ...]

class MultidisciplinaryFeasible[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V], top: N, *, analysis: Optional[Analysis[N, V]] = None)[source]

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

Per cycle, the closures folded into one MDA nested in top, and each declared problem nested in that MDA – or in top, on a cycle nothing was bound on.

combines_declared: ClassVar[bool] = False

Whether the final may Combine a declared problem into another, so each must combine as the top does; a level that only nests them says False, and then takes a problem combining as nothing.

combining(opened, closures)[source]

The ops placing what lies in the scope, read off opened, the graph the cutting leaves; closures is the problems it bound.

class IndividualFeasible[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V], top: N, *, analysis: Optional[Analysis[N, V]] = None)[source]

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

top owns the coupling copies and drives the gaps to zero; each declared problem is a solve of its own inside its iteration.

combines_declared: ClassVar[bool] = False

Whether the final may Combine a declared problem into another, so each must combine as the top does; a level that only nests them says False, and then takes a problem combining as nothing.

combining(opened, closures)[source]

The ops placing what lies in the scope, read off opened, the graph the cutting leaves; closures is the problems it bound.

class Simultaneous[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V], top: N, *, analysis: Optional[Analysis[N, V]] = None)[source]

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

top absorbs every problem under it.

combining(opened, closures)[source]

The ops placing what lies in the scope, read off opened, the graph the cutting leaves; closures is the problems it bound.

class Analysis[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V])[source]

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

Per cycle, the closures folded into one, and each declared problem nested in it. A cycle nothing was bound on is left as it is: its one problem closes it.

combines_declared: ClassVar[bool] = False

Whether the final may Combine a declared problem into another, so each must combine as the top does; a level that only nests them says False, and then takes a problem combining as nothing.

combining(opened, closures)[source]

The ops placing what lies in the scope, read off opened, the graph the cutting leaves; closures is the problems it bound.

one_mda[N: Label](op: Architecture, opened: NestingGraph[N, Any], cycle: OnCycle[N], within: Optional[N])[source]

A cycle’s closures folded into its first, the MDA, nested in within if given, and each declared problem nested in the MDA; with no closure, each nested in within, or left as it is.

Return type:

tuple[GraphOp, ...]

cuts_per_cycle_boxed[N: Label, V: Place](graph: NestingGraph[N, V], boxes: Boxes[N, V], rule: CutRule[N, V])[source]

cuts_per_cycle over the graph with each selected problem contracted with its body (NestingGraph.contract), together with every problem lying inside it; a body no selected problem brings is contracted alone, so nothing inside a body is cut. Every box is mapped back to its members: on a cycle, its function nodes in binding order; as a reader, those that read the variable – under check_implicit_models always its body, since a problem reads nothing from outside its box. In the graph’s own names.

Return type:

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

per_functional_cycle_boxed[N: Label, V: Place](graph: NestingGraph[N, V], boxes: Boxes[N, V], rule: CutRule[N, V])[source]

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

Return type:

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

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

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

None: the function nodes alone are seen.

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

The problems to fold, in binding order.

Return type:

tuple[N, ...]

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

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

Every problem of the graph handed – a discipline under check_implicit_models, and under an architecture every implicit model in its scope.

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

The problems to fold, in binding order.

Return type:

tuple[N, ...]

class Solves[N: Label, V: Place](names: tuple[N, ...])[source]

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

These, by name.

names: tuple[N, ...]
folded(graph: NestingGraph[N, V])[source]

The problems to fold, in binding order.

Return type:

tuple[N, ...]

class MDF[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V], top: N, *, analysis: Optional[Analysis[N, V]] = None)[source]

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

Multidisciplinary feasible over the disciplines.

boxes: AbstractVar[Boxes[N, V]] = disciplines

Which solves in the scope the rule sees as one function each.

class IDF[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V], top: N, *, analysis: Optional[Analysis[N, V]] = None)[source]

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

Individual discipline feasible over the disciplines.

boxes: AbstractVar[Boxes[N, V]] = disciplines

Which solves in the scope the rule sees as one function each.

class SAND[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V], top: N, *, analysis: Optional[Analysis[N, V]] = None)[source]

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

Simultaneous analysis and design over the bodies: the states are the optimiser’s outright, so a solve’s own loop needs no cut.

boxes: AbstractVar[Boxes[N, V]] = bodies

Which solves in the scope the rule sees as one function each.

class MDA[N: Label, V: Place](rule: CutRule[N, V], closing: Closing[N, V])[source]

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

A multidisciplinary analysis over the disciplines: each implicit model keeps its own solver, and one closure per cycle iterates the states between them.

boxes: AbstractVar[Boxes[N, V]] = disciplines

Which solves in the scope the rule sees as one function each.