Skip to content

Native relational execution and observations

Argument-based field and finite-step execution, native tangents, prepared patterns and hypothetical support/state events.

Part of Regional and relational SDK workflow index. Section links remain stable; hypotheses and model changes remain local to each result.

Execute the conditional relational model

This preparation is independent of the six-node regional observation:

from tnfr.sdk import Network, RelationalExchangeModel
import networkx as nx

graph = nx.path_graph(3)
for node, form, capacity in ((0, 0.1, 1.0), (1, 0.0, 0.0), (2, -0.1, 2.0)):
    graph.nodes[node].update(EPI=form, theta=0.0, nu_f=capacity)
network = Network(graph)
model = RelationalExchangeModel(storage_scale=1.0)

field = network.relational_exchange(model)  # detached, no graph mutation
step = network.step_relational(model, dt=0.01)  # one joint Euler step

Capacity and support are held; each Euler step validates its full proposal before committing. Evaluation is read-only. This explicit joint model does not change evolve or StudySpec operator-word semantics. Its structural dt is neither a word count nor a calibrated laboratory second.

The default acute phase domain has two explicit wider alternatives. The first requires certified positive real parts of relative neighbor resultants:

wider_model = RelationalExchangeModel(
    storage_scale=1.0, phase_domain="positive_resultant"
)
wider_field = network.relational_exchange(wider_model)
lower_bounds = wider_field.resultant_real_lower_bounds  # exact fractions

The regular option also admits negative real parts when the imaginary part is resolved away from zero. For example, this two-node phase gap is nonacute:

regular_graph = nx.path_graph(2)
for node in regular_graph:
    regular_graph.nodes[node].update(EPI=0.1 * node, theta=2.1 * node, nu_f=1.0)
regular_network = Network(regular_graph)
regular_model = RelationalExchangeModel(1.0, phase_domain="regular")
regular_field = regular_network.relational_exchange(regular_model)
ray_margins = regular_field.resultant_regular_margin_lower_bounds
regular_step = regular_network.step_relational(regular_model, dt=0.01)
segment_margins = regular_step.segment_resultant_regular_margin_lower_bounds

Both wider options retain exact admission bounds. The regular option rejects zero resultants, the nonpositive-real branch ray and unresolved numerical cases; it uses the same captured relative phase in pressure and metric. The step additionally checks its entire represented straight proposal chord.

A positive-resultant certificate can admit some nonacute edges. An inconclusive bound is not proof of a singularity. Successful step admission also does not promise decreasing storage, exact ODE integration or stability. Inspect retained balance defects and preserve the supplied coefficients and phase domain. The execution contract owns state/support admission, segment margins, atomicity and numerical limits; the derivation owns the conditional law and stronger recovery theorems.

Inspect a moving source at phase consensus

Equal phases do not require equal form or a stationary network. Read the complete local derivative while keeping the actual initial rates:

import networkx as nx
from tnfr.sdk import Network, RelationalExchangeModel, relational_report_to_dict

source_graph = nx.path_graph(3)
for node, form, capacity in ((0, 1, 1), (1, -0.5, 2), (2, 0, 0.5)):
    source_graph.nodes[node].update(EPI=form, theta=0, nu_f=capacity)
tangent = Network(source_graph).relational_consensus_tangent(
    RelationalExchangeModel(1)
)
assert any(tangent.field.form_rate) and any(tangent.field.phase_rate)
assert len(tangent.generator) == 6  # all three form and three phase coordinates
tangent_evidence = relational_report_to_dict(tangent)

The source is observed without a time step. The Jacobian describes its local response; it does not keep the later nonlinear evolution at phase consensus. For exactly uniform form with nonuniform phases, use the separate relational_uniform_tangent admission. Both share their derivative builder and retain numerical residuals. See the tangent contract before using either matrix in a linear approximation.

Observe a prepared relational pattern

Continue with this network, graph and model. Supply reference phases and regions rather than interpreting the observer as a pattern detector:

from tnfr.sdk import export_to_json, relational_report_to_dict

pattern = network.relational_pattern(
    model,
    reference_phase={node: 0.0 for node in graph},
    regions=(tuple(graph),),
)
region = pattern.regions[0]
form_deformation = region.form_norm_squared
phase_deformation = region.phase_norm_squared
signed_exchange = region.work.exchange  # Positive: phase storage toward form.
boundary = region.boundary
if boundary.weighted_rate_unavailable_reason is None:
    phase_rate = boundary.phase_weighted_rate
    phase_rounding_residual = boundary.phase_rate_residual
response = region.phase_response  # Unweighted rates, also at zero capacity.
mean_phase_rate = response.mean_rate
mobility_form_contribution = response.covariance_rate
covariance_squared_bound = response.covariance_rate_squared_bound
export_to_json(relational_report_to_dict(pattern), "relational-pattern.json")

The report evaluates one fresh field without advancing the graph. Reference errors use supplied real lifts; keep the same frame when comparing snapshots. Overlapping regions cannot be summed as a partition. Optional ordered cycles add winding observations through the shared winding owner.

Work, boundary rates and transport have distinct availability conditions. The zero-capacity node above intentionally makes some quantities unavailable while form/phase geometry remains observable. Check explicit reasons and None values; do not replace them with zeros. phase_response retains unweighted rates even at zero capacity. The report contract centralizes fields, reconstruction, units and support restrictions.

relational_report_to_dict supplies the versioned tnfr.relational-report.v1 envelope with exact rational data. export_to_json writes detached observations; neither function supplies a restart file or authenticated source record.

Compare a supplied connection

import networkx as nx
from tnfr.sdk import Network, RelationalExchangeModel, relational_report_to_dict

left = nx.path_graph(("a", "inside_a"))
right = nx.path_graph(("b", "inside_b"))
for component in (left, right):
    for node in component:
        component.nodes[node].update(EPI=0.0, theta=0.0, nu_f=1.0)
left.nodes["inside_a"]["EPI"] = 1 / 256
attachment = Network(left).relational_attachment(
    Network(right), RelationalExchangeModel(1), bridge=("a", "b")
)
form_rate_change = attachment.form_rate_change  # Exact represented differences.
port_before, port_after = attachment.ports[0].before, attachment.ports[0].after
report = relational_report_to_dict(attachment)
loss_rate_change = attachment.continuous_loss_change
supply = attachment.assess_supply(0)  # Explicitly suppose no event work is supplied.
supply_report = relational_report_to_dict(supply)

Both components are evaluated against their hypothetical joined graph; neither input changes. Labels must be disjoint, and the support/model must meet the attachment contract. The result retains before/after port state, full fields, rate differences and transport/reset accounting. Equal endpoint form and phase need not imply equal rates after attachment: degree and phase metric also enter the declared law. This comparison does not select or create connections autonomously.

assess_supply compares declared work with the captured storage increment. Its supply_margin is work minus required supply; a nonnegative margin satisfies the represented balance under an additional passivity premise. In this example the endpoint values agree, so zero work covers the zero storage increment even though the port rates change. Negative work means extraction. No work source or event time is inferred, and a change in the continuous loss rate is not available event work. The exact fractions describe captured numerical values; they do not certify ideal trigonometric storage or physical energy.

Compare a supplied bridge relocation

import networkx as nx
from tnfr.sdk import Network, RelationalExchangeModel, relational_report_to_dict

graph = nx.path_graph(4)
for node, form in enumerate((0.0, 2.0, 0.0, 1.0)):
    graph.nodes[node].update(EPI=form, theta=0.0, nu_f=1.0)
relocation = Network(graph).relational_relocation(
    RelationalExchangeModel(1), remove_bridge=(1, 2), add_bridge=(0, 3)
)
assert relocation.components == ((0, 1), (2, 3))
assert relocation.storage_change == -1.5
budget = relocation.assess_supply(0)
assert budget.represented_balance_satisfied
report = relational_report_to_dict(relocation)

The graph remains the original path. The comparison retains fresh fields for the original support and hypothetical exchanged support, both cuts and unique before/after port cards. The removed bridge defines the ordered components; the new missing edge must join those same components in that order. All their internal edges and primitive states remain unchanged. The relocation contract owns admission and report details.

Here the stored cost decreases by 3/2. The assessment's required_supply is therefore negative: it is the signed lower bound on net supplied work, rather than a clipped positive cost. Work -3/2 would exactly balance declared extraction; zero work also satisfies the additional passivity premise. This static comparison does not execute the exchange, choose its time or certify recovery of a pattern. The conditional two-C5 result has separate theorem hypotheses; this general graph example does not inherit them.

Compare a joint state and support reset

Unlike a frozen-state attachment, a complete action can change form or phase while adding a link. Compare the actual stored endpoints through one owner:

from fractions import Fraction
import networkx as nx
from tnfr.sdk import Network, relational_report_to_dict

before_graph = nx.Graph(((0, 1), (2, 3)))
for node, form in enumerate((0.75, 0.25, 0.25, 0.75)):
    before_graph.nodes[node].update(
        EPI=form, theta=0.0, nu_f=1.0, delta_nfr=0.0
    )
after_graph = before_graph.copy()
for node, form in enumerate((0.625, 0.375, 0.375, 0.625)):
    after_graph.nodes[node]["EPI"] = form
after_graph.add_edge(0, 2, weight=0.5)
reset = Network(before_graph).relational_reset(
    Network(after_graph), storage_scale=1.0
)
assert reset.form_state_change == Fraction(-3, 16)
assert reset.form_support_change == Fraction(1, 64)
assert reset.storage_change == Fraction(-11, 64)
assert reset.identity_residual == 0
payload = relational_report_to_dict(reset)

These are supplied snapshots, not execution of an authenticated operator or an autonomous connection. The positive edge cost is offset by form change in the complete comparison. The report does not credit earlier dissipation as stored work or prove separate passivity of intermediate events. Nonunit support is admissible to this observation but rejects the current unit-support relational executor. Real UM and RA-then-UM controls are linked from the reset contract.