tgi-foundation 0.2.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tgi/__init__.py +7 -0
- tgi/__main__.py +194 -0
- tgi/acquisition_history.py +45 -0
- tgi/acquisition_history_check.py +51 -0
- tgi/acquisition_monitor.py +66 -0
- tgi/acquisition_monitor_check.py +78 -0
- tgi/acquisition_projection.py +70 -0
- tgi/acquisition_projection_check.py +93 -0
- tgi/acquisition_role_cells.py +53 -0
- tgi/acquisition_role_constraints.py +13 -0
- tgi/acquisition_role_constraints_check.py +66 -0
- tgi/acquisition_snapshot.py +35 -0
- tgi/acquisition_stream.py +21 -0
- tgi/acquisition_witness.py +117 -0
- tgi/actuation_goal_frontier.py +117 -0
- tgi/actuation_goal_frontier_check.py +147 -0
- tgi/actuation_goal_workflow.py +159 -0
- tgi/actuation_sequence_feedback.py +41 -0
- tgi/actuation_sequence_feedback_check.py +43 -0
- tgi/ask_certificate.py +74 -0
- tgi/bands.py +59 -0
- tgi/capacity_graph.py +70 -0
- tgi/closed_actuation_goal_frontier.py +13 -0
- tgi/closed_actuation_goal_frontier_check.py +19 -0
- tgi/closed_actuation_goal_workflow.py +159 -0
- tgi/closure.py +202 -0
- tgi/compact_acquisition_map.py +68 -0
- tgi/compact_acquisition_map_check.py +91 -0
- tgi/compact_complete_role_core.py +36 -0
- tgi/compact_complete_role_core_check.py +62 -0
- tgi/compact_measured_path.py +84 -0
- tgi/compact_role_observation.py +13 -0
- tgi/compact_role_observation_check.py +66 -0
- tgi/compatible_joins.py +33 -0
- tgi/complete_role_core.py +53 -0
- tgi/complete_role_core_check.py +54 -0
- tgi/context_family_selection.py +45 -0
- tgi/context_family_selection_check.py +32 -0
- tgi/context_family_separation.py +43 -0
- tgi/context_family_separation_check.py +47 -0
- tgi/contextual_isometry.py +62 -0
- tgi/contextual_isometry_check.py +54 -0
- tgi/continuation_checkpoint.py +75 -0
- tgi/continuation_cycle.py +102 -0
- tgi/continuation_goal_frontier.py +13 -0
- tgi/continuation_goal_frontier_check.py +19 -0
- tgi/continuation_goal_workflow.py +159 -0
- tgi/continuation_learning.py +36 -0
- tgi/continuation_learning_check.py +53 -0
- tgi/correspondence.py +76 -0
- tgi/cross_action_correspondence.py +182 -0
- tgi/cross_action_correspondence_check.py +92 -0
- tgi/cross_view_identity_map.py +41 -0
- tgi/cross_view_identity_map_check.py +48 -0
- tgi/derivation.py +74 -0
- tgi/empirical_transport.py +74 -0
- tgi/empirical_transport_check.py +78 -0
- tgi/events.py +36 -0
- tgi/evidence_response.py +24 -0
- tgi/evidence_response_check.py +33 -0
- tgi/exact_field.py +101 -0
- tgi/experience.py +68 -0
- tgi/experience_cli.py +44 -0
- tgi/feedback_update.py +32 -0
- tgi/feedback_update_check.py +38 -0
- tgi/formation.py +74 -0
- tgi/frame_cli.py +26 -0
- tgi/frame_engine.py +214 -0
- tgi/functional_capacity.py +74 -0
- tgi/functional_capacity_check.py +110 -0
- tgi/functional_transition.py +40 -0
- tgi/functional_transition_check.py +58 -0
- tgi/geometry.py +143 -0
- tgi/grounding.py +285 -0
- tgi/guarded_word_closure.py +148 -0
- tgi/guarded_word_closure_check.py +171 -0
- tgi/guarded_word_goal_frontier.py +13 -0
- tgi/guarded_word_goal_frontier_check.py +19 -0
- tgi/guarded_word_goal_workflow.py +160 -0
- tgi/identity.py +32 -0
- tgi/incidence.py +155 -0
- tgi/incremental.py +134 -0
- tgi/intervention_composition.py +63 -0
- tgi/intervention_composition_check.py +84 -0
- tgi/intervention_continuity.py +43 -0
- tgi/intervention_continuity_check.py +56 -0
- tgi/intervention_correspondence.py +156 -0
- tgi/intervention_correspondence_check.py +80 -0
- tgi/intervention_edit_contrast.py +27 -0
- tgi/intervention_edit_contrast_check.py +41 -0
- tgi/intervention_experiment.py +62 -0
- tgi/intervention_experiment_check.py +78 -0
- tgi/intervention_resolution.py +45 -0
- tgi/intervention_resolution_check.py +70 -0
- tgi/intervention_roles.py +83 -0
- tgi/intervention_roles_check.py +91 -0
- tgi/intervention_scope.py +34 -0
- tgi/intervention_sequence_experiment.py +71 -0
- tgi/intervention_sequence_experiment_check.py +97 -0
- tgi/interventions.py +240 -0
- tgi/joint_correspondence.py +73 -0
- tgi/joint_frontier_acquisition.py +114 -0
- tgi/joint_frontier_acquisition_check.py +116 -0
- tgi/joint_goal_observation.py +49 -0
- tgi/joint_goal_observation_check.py +55 -0
- tgi/joint_goal_traversal.py +101 -0
- tgi/joint_goal_traversal_check.py +114 -0
- tgi/joint_observed_laws.py +40 -0
- tgi/joint_observed_laws_check.py +63 -0
- tgi/joint_temporal_candidates.py +40 -0
- tgi/joint_temporal_candidates_check.py +68 -0
- tgi/lineage_knowledge.py +29 -0
- tgi/lineage_knowledge_check.py +41 -0
- tgi/lineage_state.py +39 -0
- tgi/lineage_state_check.py +47 -0
- tgi/local_acquisition_ownership.py +65 -0
- tgi/local_acquisition_runtime.py +119 -0
- tgi/local_acquisition_selection.py +41 -0
- tgi/local_acquisition_transition.py +50 -0
- tgi/local_acquisition_transition_check.py +80 -0
- tgi/local_edit_transport_classes.py +220 -0
- tgi/local_edit_transport_classes_check.py +128 -0
- tgi/local_evidence_persistence.py +67 -0
- tgi/measured_actuation_transition.py +56 -0
- tgi/measured_actuation_transition_check.py +81 -0
- tgi/measured_capacity.py +61 -0
- tgi/measured_context.py +52 -0
- tgi/measured_context_check.py +65 -0
- tgi/measured_context_laws.py +75 -0
- tgi/measured_context_laws_check.py +91 -0
- tgi/measured_context_layout.py +49 -0
- tgi/measured_occurrence_path.py +70 -0
- tgi/momentum.py +43 -0
- tgi/observation_context_laws.py +32 -0
- tgi/observation_context_laws_check.py +40 -0
- tgi/observation_epochs.py +35 -0
- tgi/observation_epochs_check.py +51 -0
- tgi/observation_point.py +92 -0
- tgi/observation_projection.py +45 -0
- tgi/observation_projection_check.py +48 -0
- tgi/observed_actuation_cycle.py +114 -0
- tgi/observed_actuation_discovery.py +41 -0
- tgi/observed_actuation_discovery_check.py +54 -0
- tgi/observed_actuation_learning.py +71 -0
- tgi/observed_actuation_learning_check.py +73 -0
- tgi/observed_actuation_runtime.py +114 -0
- tgi/observed_context_actions.py +66 -0
- tgi/observed_context_actions_check.py +81 -0
- tgi/observed_joint_state.py +52 -0
- tgi/observed_joint_state_check.py +55 -0
- tgi/observed_refinement.py +43 -0
- tgi/observed_response.py +20 -0
- tgi/observed_response_check.py +27 -0
- tgi/observed_role_core.py +41 -0
- tgi/observed_role_core_check.py +54 -0
- tgi/occurrence_route.py +56 -0
- tgi/operator_windows.py +84 -0
- tgi/operator_windows_check.py +111 -0
- tgi/organization.py +484 -0
- tgi/organization_check.py +143 -0
- tgi/organization_cli.py +77 -0
- tgi/organization_inventory_check.py +82 -0
- tgi/organization_snapshot.py +50 -0
- tgi/path_isometry.py +82 -0
- tgi/path_temporal_feasibility.py +69 -0
- tgi/phase_evidence.py +100 -0
- tgi/port_distinction_exploration.py +37 -0
- tgi/port_distinction_exploration_check.py +40 -0
- tgi/proofcheck.py +117 -0
- tgi/provenance.py +19 -0
- tgi/recent_observation.py +145 -0
- tgi/relational.py +222 -0
- tgi/resonance.py +114 -0
- tgi/response_eligibility.py +46 -0
- tgi/response_eligibility_check.py +55 -0
- tgi/response_interval_order.py +59 -0
- tgi/response_interval_order_check.py +92 -0
- tgi/response_readout.py +53 -0
- tgi/response_readout_check.py +73 -0
- tgi/role_bundle.py +31 -0
- tgi/role_bundle_check.py +20 -0
- tgi/role_candidates.py +47 -0
- tgi/role_candidates_check.py +57 -0
- tgi/role_eligibility.py +34 -0
- tgi/role_eligibility_check.py +46 -0
- tgi/role_feedback.py +15 -0
- tgi/role_feedback_check.py +23 -0
- tgi/role_history.py +37 -0
- tgi/role_history_check.py +51 -0
- tgi/role_projection.py +16 -0
- tgi/role_projection_check.py +85 -0
- tgi/role_proposal.py +39 -0
- tgi/role_proposal_check.py +51 -0
- tgi/role_readout.py +31 -0
- tgi/role_readout_check.py +51 -0
- tgi/role_response.py +34 -0
- tgi/role_response_check.py +40 -0
- tgi/role_work.py +54 -0
- tgi/scoped_sequence_experiment.py +20 -0
- tgi/scoped_sequence_experiment_check.py +33 -0
- tgi/separation.py +74 -0
- tgi/separation_check.py +87 -0
- tgi/sequence_prefix_feedback.py +57 -0
- tgi/sequence_prefix_feedback_check.py +79 -0
- tgi/source_intervals.py +85 -0
- tgi/source_intervals_check.py +97 -0
- tgi/spatial.py +109 -0
- tgi/spatial_action_observation.py +88 -0
- tgi/spatial_action_relation.py +53 -0
- tgi/spatial_action_relation_check.py +45 -0
- tgi/spatial_action_relation_cycle.py +84 -0
- tgi/spatial_action_relation_migration.py +41 -0
- tgi/spatial_action_relation_migration_bundle.py +60 -0
- tgi/spatial_contextual_action_cycle.py +130 -0
- tgi/spatial_contextual_action_local.py +79 -0
- tgi/spatial_contextual_action_phase.py +81 -0
- tgi/spatial_contextual_action_phase_check.py +81 -0
- tgi/spatial_direct_action_cycle.py +98 -0
- tgi/spatial_direct_action_relation.py +60 -0
- tgi/spatial_direct_action_relation_check.py +67 -0
- tgi/spatial_local_action_cycle.py +62 -0
- tgi/spatial_local_action_relation.py +66 -0
- tgi/spatial_temporal_action_cycle.py +116 -0
- tgi/spatial_temporal_action_local.py +77 -0
- tgi/spatial_temporal_action_phase.py +89 -0
- tgi/spatial_temporal_action_phase_check.py +94 -0
- tgi/structural_append_closure.py +99 -0
- tgi/structural_append_closure_check.py +106 -0
- tgi/structural_continuation_closure.py +93 -0
- tgi/structural_continuation_closure_check.py +108 -0
- tgi/temporal_candidate_spectrum.py +57 -0
- tgi/temporal_candidate_spectrum_check.py +94 -0
- tgi/temporal_correspondence.py +41 -0
- tgi/temporal_correspondence_check.py +56 -0
- tgi/temporal_projection.py +41 -0
- tgi/temporal_projection_check.py +56 -0
- tgi/transport.py +294 -0
- tgi/transport_cli.py +27 -0
- tgi/unlabeled_port_classes.py +199 -0
- tgi/unlabeled_port_classes_check.py +113 -0
- tgi/unobserved_action_selection.py +47 -0
- tgi/unobserved_action_selection_check.py +40 -0
- tgi/verification.py +98 -0
- tgi/witness_function.py +62 -0
- tgi/witness_probe.py +50 -0
- tgi/witness_probe_feedback.py +106 -0
- tgi/witness_response.py +67 -0
- tgi_foundation-0.2.0.dev0.dist-info/METADATA +30 -0
- tgi_foundation-0.2.0.dev0.dist-info/RECORD +252 -0
- tgi_foundation-0.2.0.dev0.dist-info/WHEEL +5 -0
- tgi_foundation-0.2.0.dev0.dist-info/licenses/LICENSE +3 -0
- tgi_foundation-0.2.0.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Native visible intervention-role partitions; no world-object labels."""
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from tgi.identity import decode,encode
|
|
4
|
+
from tgi.organization import OMEGA_CRIT
|
|
5
|
+
from tgi.acquisition_snapshot import acquisition_snapshot as snapshot
|
|
6
|
+
from tgi.acquisition_witness import certify_raw_acquisition_witness as certify_acquisition_witness
|
|
7
|
+
from tgi.compact_measured_path import _decimal_count
|
|
8
|
+
from tgi.role_work import RoleSearchBudget
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _cells(acquisition,groups,measurements):
|
|
12
|
+
view=snapshot(acquisition);witness=certify_acquisition_witness(view,measurements)
|
|
13
|
+
if not isinstance(groups,list) or not groups:raise ValueError('Groups required')
|
|
14
|
+
lookup={(r['source'],r['frame']):r for r in measurements}
|
|
15
|
+
if len(lookup)!=len(measurements):raise ValueError('One full-frame measurement required')
|
|
16
|
+
expected={(s,i) for s,(frames,_) in view.episodes.items() for i in range(len(frames))}
|
|
17
|
+
if set(lookup)!=expected:raise ValueError('Complete measurement coverage required')
|
|
18
|
+
for (s,i),r in lookup.items():
|
|
19
|
+
if r['start']!=0 or r['stop']!=len(view.episodes[s][0][i]):raise ValueError('Whole-frame measurements required')
|
|
20
|
+
ports=[];used=set();records=[];diversity={};windows=[]
|
|
21
|
+
for group in groups:
|
|
22
|
+
if not isinstance(group,list) or not group:raise ValueError('Nonempty view group required')
|
|
23
|
+
cells={};actions=set();action_bounds=set();context_windows={};before_values={}
|
|
24
|
+
for spec in group:
|
|
25
|
+
if not isinstance(spec,dict) or set(spec)!={'port','source'}:raise ValueError('Invalid view layout')
|
|
26
|
+
port=spec['port'];source=spec['source']
|
|
27
|
+
encode(port)
|
|
28
|
+
if not isinstance(port,str) or not port or port in cells or source in used or source not in view.episodes:raise ValueError('Duplicate or missing view source')
|
|
29
|
+
frames=view.episodes[source][0]
|
|
30
|
+
if len(frames)!=3:raise ValueError('Exactly before/action/after frames required')
|
|
31
|
+
used.add(source);actions.add(decode(frames[1]))
|
|
32
|
+
if port not in ports:ports.append(port);diversity[port]=set()
|
|
33
|
+
before,action,after=(lookup[source,i] for i in range(3))
|
|
34
|
+
action_bounds.add((action['clock'],action['lower'],action['upper']))
|
|
35
|
+
context_windows[port]=(before['clock'],before['lower'],after['upper'])
|
|
36
|
+
before_values[port]=frames[0]
|
|
37
|
+
certain=len({before['clock'],action['clock'],after['clock']})==1 and before['upper']<=action['lower'] and action['upper']<=after['lower']
|
|
38
|
+
value=int(frames[0]!=frames[2]) if certain else None
|
|
39
|
+
cells[port]=value
|
|
40
|
+
|
|
41
|
+
if len(actions)!=1 or len(action_bounds)!=1:raise ValueError('One consistent measured action per group required')
|
|
42
|
+
windows.append(next(iter(action_bounds)))
|
|
43
|
+
records.append({'action':next(iter(actions)),'cells':cells,'windows':context_windows,'before':before_values})
|
|
44
|
+
if used!=set(view.episodes):raise ValueError('Complete source coverage required')
|
|
45
|
+
for index,r in enumerate(records):
|
|
46
|
+
for port,value in list(r['cells'].items()):
|
|
47
|
+
clock,lower,upper=r['windows'][port]
|
|
48
|
+
if any(other_clock!=clock or not (other_upper<lower or other_lower>upper) for j,(other_clock,other_lower,other_upper) in enumerate(windows) if j!=index):value=None
|
|
49
|
+
r['cells'][port]=value
|
|
50
|
+
if value==1:diversity[port].add(r['before'][port])
|
|
51
|
+
rows=[{'action':r['action'],'cells':[r['cells'].get(p) for p in ports]} for r in records]
|
|
52
|
+
return witness,ports,rows,[len(diversity[p]) for p in ports]
|
|
53
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Exact full original binary role domain without enumerating its completions."""
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from tgi.acquisition_snapshot import acquisition_snapshot as snapshot
|
|
4
|
+
from tgi.acquisition_role_cells import _cells
|
|
5
|
+
from tgi.role_work import RoleSearchBudget
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def certify_compact_role_constraints(model,groups,measurements,*,max_search_steps=None):
|
|
9
|
+
budget=RoleSearchBudget(max_search_steps)
|
|
10
|
+
with budget.scope():
|
|
11
|
+
budget.consume();groups,measurements=deepcopy((groups,measurements));witness,ports,rows,diversity=_cells(snapshot(model),groups,measurements)
|
|
12
|
+
budget.consume_many(sum(len(r['cells']) for r in rows));free=sum(x is None for r in rows for x in r['cells'])
|
|
13
|
+
return {'policy':'compact_acquisition_role_constraints_v119','groups':groups,'witness':witness,'ports':ports,'rows':rows,'changed_before_diversity':diversity,'completions':{'base':2,'exponent':free},'status':'UNCERTAIN_ATTRIBUTION' if free else 'DETERMINED_VISIBLE_ROLES'}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Independent source/cell/complete-partition verifier for visible roles."""
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from tgi.identity import decode,encode
|
|
4
|
+
from tgi.organization import OMEGA_CRIT
|
|
5
|
+
from tgi.acquisition_snapshot import acquisition_snapshot as snapshot
|
|
6
|
+
from tgi.acquisition_witness import verify_raw_acquisition_witness as verify_acquisition_witness
|
|
7
|
+
from tgi.compact_measured_path import _decimal_count
|
|
8
|
+
from tgi.frame_engine import canonical
|
|
9
|
+
from tgi.role_work import RoleSearchBudget
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def verify_compact_role_constraints(acquisition,groups,measurements,certificate,*,max_search_steps=None):
|
|
13
|
+
budget=RoleSearchBudget(max_search_steps)
|
|
14
|
+
with budget.scope():
|
|
15
|
+
budget.consume()
|
|
16
|
+
try:
|
|
17
|
+
fields={'policy','groups','witness','ports','rows','changed_before_diversity','completions','status'}
|
|
18
|
+
c=certificate
|
|
19
|
+
if set(c)!=fields or c['policy']!='compact_acquisition_role_constraints_v119' or canonical(c['groups'])!=canonical(groups):return False
|
|
20
|
+
view=snapshot(acquisition);groups=deepcopy(groups);measurements=deepcopy(measurements)
|
|
21
|
+
if not verify_acquisition_witness(view,measurements,c['witness']):return False
|
|
22
|
+
if not isinstance(groups,list) or not groups:return False
|
|
23
|
+
measured={};expected={(s,i) for s,(frames,_) in view.episodes.items() for i in range(len(frames))}
|
|
24
|
+
for r in measurements:
|
|
25
|
+
k=(r['source'],r['frame'])
|
|
26
|
+
if k in measured or r['start']!=0 or r['stop']!=len(view.episodes[k[0]][0][k[1]]):return False
|
|
27
|
+
measured[k]=r
|
|
28
|
+
if set(measured)!=expected:return False
|
|
29
|
+
ports=[];used=set();cells=[];raw_inputs={};operations=[]
|
|
30
|
+
for group in groups:
|
|
31
|
+
if not isinstance(group,list) or not group:return False
|
|
32
|
+
observed={};action_values=[];op_bounds=set();windows={};before_values={}
|
|
33
|
+
for spec in group:
|
|
34
|
+
if not isinstance(spec,dict) or set(spec)!={'port','source'}:return False
|
|
35
|
+
p,s=spec['port'],spec['source']
|
|
36
|
+
encode(p)
|
|
37
|
+
if not isinstance(p,str) or not p or p in observed or s in used or s not in view.episodes:return False
|
|
38
|
+
frames=view.episodes[s][0]
|
|
39
|
+
if len(frames)!=3:return False
|
|
40
|
+
used.add(s)
|
|
41
|
+
if p not in ports:ports.append(p);raw_inputs[p]=set()
|
|
42
|
+
action_values.append(decode(frames[1]));bounds=[measured[s,i] for i in range(3)]
|
|
43
|
+
op_bounds.add((bounds[1]['clock'],bounds[1]['lower'],bounds[1]['upper']))
|
|
44
|
+
windows[p]=(bounds[0]['clock'],bounds[0]['lower'],bounds[2]['upper']);before_values[p]=frames[0]
|
|
45
|
+
value=None
|
|
46
|
+
if all(r['clock']==bounds[0]['clock'] for r in bounds) and bounds[0]['upper']<=bounds[1]['lower'] and bounds[1]['upper']<=bounds[2]['lower']:
|
|
47
|
+
value=0 if frames[0]==frames[2] else 1
|
|
48
|
+
observed[p]=value
|
|
49
|
+
|
|
50
|
+
if len(set(action_values))!=1 or len(op_bounds)!=1:return False
|
|
51
|
+
operations.append(next(iter(op_bounds)));cells.append((action_values[0],observed,windows,before_values))
|
|
52
|
+
if used!=set(view.episodes) or canonical(ports)!=canonical(c['ports']):return False
|
|
53
|
+
for index,(_,values,windows,before_values) in enumerate(cells):
|
|
54
|
+
for port in values:
|
|
55
|
+
clock,begin,end=windows[port]
|
|
56
|
+
for other,(op_clock,op_begin,op_end) in enumerate(operations):
|
|
57
|
+
if other==index:continue
|
|
58
|
+
if op_clock!=clock or not (op_end<begin or end<op_begin):values[port]=None;break
|
|
59
|
+
if values[port]==1:raw_inputs[port].add(before_values[port])
|
|
60
|
+
rows=[{'action':a,'cells':[values.get(p) for p in ports]} for a,values,_,_ in cells]
|
|
61
|
+
diversity=[len(raw_inputs[p]) for p in ports]
|
|
62
|
+
if canonical(rows)!=canonical(c['rows']) or canonical(diversity)!=canonical(c['changed_before_diversity']):return False
|
|
63
|
+
budget.consume_many(sum(len(r['cells']) for r in rows));free=sum(value is None for row in rows for value in row['cells'])
|
|
64
|
+
expected={'base':2,'exponent':free}
|
|
65
|
+
return canonical(c['completions'])==canonical(expected) and c['status']==('UNCERTAIN_ATTRIBUTION' if free else 'DETERMINED_VISIBLE_ROLES')
|
|
66
|
+
except (ValueError,TypeError,KeyError,IndexError,AttributeError):return False
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Immutable original frame evidence; explicitly cannot authorize knowledge."""
|
|
2
|
+
from types import MappingProxyType
|
|
3
|
+
from .organization import RawOrganization
|
|
4
|
+
from .organization_snapshot import _Frames
|
|
5
|
+
from .frame_engine import Receipt
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AcquisitionSnapshot(RawOrganization):
|
|
9
|
+
_acquisition_only=True
|
|
10
|
+
|
|
11
|
+
def __init__(self,engine):
|
|
12
|
+
if not isinstance(engine,RawOrganization):raise TypeError('Original acquisition model required')
|
|
13
|
+
if getattr(engine.frames,'_pending',None):raise ValueError('Pending frame is not complete acquisition evidence')
|
|
14
|
+
episodes=dict(engine.episodes)
|
|
15
|
+
for value in episodes.values():
|
|
16
|
+
if type(value) is not tuple or len(value)!=2 or type(value[0]) is not tuple or type(value[1]) is not tuple or any(type(f) is not tuple for f in value[0]) or any(type(r) is not Receipt for r in value[1]):raise ValueError('Immutable original episode/receipt containers required')
|
|
17
|
+
self.frames=_Frames(engine.frames.view());self.episodes=MappingProxyType(episodes)
|
|
18
|
+
self.organizations=MappingProxyType({});self.rejected_organizations=MappingProxyType({})
|
|
19
|
+
self._dirty=True;self._valid={}
|
|
20
|
+
|
|
21
|
+
def _alive(self,source):
|
|
22
|
+
if source not in self._valid:self._valid[source]=super()._alive(source)
|
|
23
|
+
return self._valid[source]
|
|
24
|
+
|
|
25
|
+
def observe(self,*args,**kwargs):raise TypeError('Acquisition snapshot is read-only')
|
|
26
|
+
def form(self,*args,**kwargs):raise TypeError('Acquisition snapshot cannot form knowledge')
|
|
27
|
+
def resolve(self,*args,**kwargs):raise TypeError('Acquisition snapshot cannot resolve knowledge')
|
|
28
|
+
def _phase_valid(self,*args,**kwargs):raise TypeError('Acquisition snapshot cannot admit knowledge phase')
|
|
29
|
+
def save(self,*args,**kwargs):raise TypeError('Persist original model, not an acquisition-only snapshot')
|
|
30
|
+
@classmethod
|
|
31
|
+
def load(cls,*args,**kwargs):raise TypeError('Load original model, then snapshot acquisition')
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def acquisition_snapshot(engine):
|
|
35
|
+
return AcquisitionSnapshot(engine)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Append-only acquisition with unchanged historical frame receipts."""
|
|
2
|
+
from .organization import RawOrganization
|
|
3
|
+
from .identity import encode,decode
|
|
4
|
+
from .frame_engine import canonical
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AcquisitionStream(RawOrganization):
|
|
8
|
+
def extend(self,source,frames):
|
|
9
|
+
"""Accept a complete new prefix; identical retries are no-ops."""
|
|
10
|
+
if not isinstance(source,str) or not source.strip():raise ValueError('Source required')
|
|
11
|
+
encode(source)
|
|
12
|
+
if not isinstance(frames,(list,tuple)) or not frames:raise ValueError('Nonempty frames required')
|
|
13
|
+
raw=tuple(map(encode,frames))
|
|
14
|
+
if any(not f for f in raw):raise ValueError('Empty frame')
|
|
15
|
+
previous,receipts=self.episodes[source]
|
|
16
|
+
if len(raw)<len(previous) or raw[:len(previous)]!=previous:raise ValueError('Historical prefix changed')
|
|
17
|
+
if not self._alive(source):raise ValueError('Broken historical evidence')
|
|
18
|
+
if raw==previous:return
|
|
19
|
+
added=self.frames.ingest_batch((decode(raw[i]),canonical([source,i])) for i in range(len(previous),len(raw)))
|
|
20
|
+
self.episodes[source]=(raw,receipts+added)
|
|
21
|
+
self._dirty=True
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Source-bound measured-interval evidence; compatibility is not object identity."""
|
|
2
|
+
from heapq import heappop,heappush
|
|
3
|
+
from .organization_snapshot import snapshot
|
|
4
|
+
from .acquisition_snapshot import acquisition_snapshot
|
|
5
|
+
from .frame_engine import canonical
|
|
6
|
+
from .identity import encode,decode
|
|
7
|
+
from .incidence import _endpoint
|
|
8
|
+
from .role_work import RoleSearchBudget
|
|
9
|
+
|
|
10
|
+
_FIELDS={'source','frame','start','stop','clock','lower','upper'}
|
|
11
|
+
|
|
12
|
+
def _inputs(model,measurements,*,raw=False):
|
|
13
|
+
view=acquisition_snapshot(model) if raw else snapshot(model)
|
|
14
|
+
if not isinstance(measurements,list):raise ValueError('Measurements must be a list')
|
|
15
|
+
records=[];seen=set()
|
|
16
|
+
for r in measurements:
|
|
17
|
+
if not isinstance(r,dict) or set(r)!=_FIELDS:raise ValueError('Invalid measurement schema')
|
|
18
|
+
for key in ('source','clock'):
|
|
19
|
+
if not isinstance(r[key],str) or not r[key].strip():raise ValueError('Measurement authority required')
|
|
20
|
+
encode(r[key])
|
|
21
|
+
if any(type(r[k]) is not int for k in ('frame','start','stop','lower','upper')):raise ValueError('Integer bounds required')
|
|
22
|
+
if r['source'] not in view.episodes:raise ValueError('Unknown source')
|
|
23
|
+
frames=view.episodes[r['source']][0]
|
|
24
|
+
if not 0<=r['frame']<len(frames) or not 0<=r['start']<r['stop']<=len(frames[r['frame']]) or r['lower']>r['upper']:raise ValueError('Invalid measurement bounds')
|
|
25
|
+
key=(r['source'],r['frame'],r['start'],r['stop'])
|
|
26
|
+
if key in seen:raise ValueError('Duplicate occurrence measurement')
|
|
27
|
+
seen.add(key);records.append(dict(r))
|
|
28
|
+
sources=[]
|
|
29
|
+
for sid,(frames,_) in sorted(view.episodes.items()):
|
|
30
|
+
if not view._alive(sid):raise ValueError('Broken source')
|
|
31
|
+
sources.append({'source':sid,'frames':list(map(decode,frames))})
|
|
32
|
+
return view,sorted(records,key=canonical),sources
|
|
33
|
+
|
|
34
|
+
def _producer_interval_pairs(records):
|
|
35
|
+
"""Closed interval sweep; all original cross-source partners survive."""
|
|
36
|
+
clocks={};pairs=[]
|
|
37
|
+
for i,r in enumerate(records):clocks.setdefault(r['clock'],[]).append(i)
|
|
38
|
+
for indices in clocks.values():
|
|
39
|
+
active={};ends=[]
|
|
40
|
+
for i in sorted(indices,key=lambda i:(records[i]['lower'],i)):
|
|
41
|
+
r=records[i];lo=r['lower']
|
|
42
|
+
while ends and ends[0][0]<lo:
|
|
43
|
+
_,j=heappop(ends);sid=records[j]['source'];del active[sid][j]
|
|
44
|
+
if not active[sid]:del active[sid]
|
|
45
|
+
for sid,bucket in active.items():
|
|
46
|
+
if sid==r['source']:continue
|
|
47
|
+
for j in bucket:
|
|
48
|
+
left,right=sorted((i,j));pairs.append({'left':left,'right':right,'intersection':[lo,min(r['upper'],records[j]['upper'])]})
|
|
49
|
+
active.setdefault(r['source'],{})[i]=None;heappush(ends,(r['upper'],i))
|
|
50
|
+
return sorted(pairs,key=lambda p:(p['left'],p['right']))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _checker_interval_pairs(records):
|
|
54
|
+
"""Independent endpoint-event reconstruction; starts precede equal ends."""
|
|
55
|
+
authorities={};edges=[]
|
|
56
|
+
for index,item in enumerate(records):
|
|
57
|
+
events=authorities.setdefault(item['clock'],[])
|
|
58
|
+
events.extend(((item['lower'],0,index),(item['upper'],1,index)))
|
|
59
|
+
for events in authorities.values():
|
|
60
|
+
live={}
|
|
61
|
+
for instant,kind,index in sorted(events):
|
|
62
|
+
item=records[index];source=item['source']
|
|
63
|
+
if kind:
|
|
64
|
+
live[source].remove(index)
|
|
65
|
+
if not live[source]:del live[source]
|
|
66
|
+
continue
|
|
67
|
+
for owner,others in live.items():
|
|
68
|
+
if owner==source:continue
|
|
69
|
+
for other in others:
|
|
70
|
+
a,b=(index,other) if index<other else (other,index)
|
|
71
|
+
edges.append({'left':a,'right':b,'intersection':[max(item['lower'],records[other]['lower']),min(item['upper'],records[other]['upper'])]})
|
|
72
|
+
live.setdefault(source,set()).add(index)
|
|
73
|
+
return sorted(edges,key=lambda e:(e['left'],e['right']))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _certify_acquisition_witness(model,measurements,*,max_search_steps=None,raw=False):
|
|
77
|
+
budget=RoleSearchBudget(max_search_steps)
|
|
78
|
+
with budget.scope():
|
|
79
|
+
view,records,sources=_inputs(model,measurements,raw=raw);occurrences=[];pairs=[]
|
|
80
|
+
for r in records:
|
|
81
|
+
budget.consume();occurrences.append(_endpoint(view,r['source'],(r['frame'],r['start'],r['stop'])))
|
|
82
|
+
budget.consume_many(len(records)*(len(records)-1)//2)
|
|
83
|
+
pairs=_producer_interval_pairs(records)
|
|
84
|
+
return {'policy':'measured_interval_witness_v1','sources':sources,'measurements':records,'occurrences':occurrences,'pairs':pairs,'status':'COMPATIBLE_PAIRS' if pairs else 'NO_COMPATIBLE_PAIR'}
|
|
85
|
+
|
|
86
|
+
def _verify_acquisition_witness(model,measurements,certificate,*,max_search_steps=None,raw=False):
|
|
87
|
+
budget=RoleSearchBudget(max_search_steps)
|
|
88
|
+
with budget.scope():
|
|
89
|
+
try:
|
|
90
|
+
view,records,sources=_inputs(model,measurements,raw=raw)
|
|
91
|
+
if set(certificate)!={'policy','sources','measurements','occurrences','pairs','status'} or certificate['policy']!='measured_interval_witness_v1':return False
|
|
92
|
+
if canonical(certificate['sources'])!=canonical(sources) or canonical(certificate['measurements'])!=canonical(records):return False
|
|
93
|
+
endpoints=[];edges=[]
|
|
94
|
+
for i,r in enumerate(records):
|
|
95
|
+
budget.consume();frames,receipts=view.episodes[r['source']];fi=r['frame'];start=r['start'];stop=r['stop'];origin=receipts[fi].origin;offset=sum(map(len,frames[:fi]))
|
|
96
|
+
endpoints.append({'frame':fi,'start':start,'stop':stop,'event_span':[offset+start,offset+stop],'identities':list(frames[fi][start:stop]),'coordinates':[[origin[0]+p,*origin[1:]] for p in range(start,stop)]})
|
|
97
|
+
budget.consume_many(len(records)*(len(records)-1)//2)
|
|
98
|
+
edges=_checker_interval_pairs(records)
|
|
99
|
+
status='COMPATIBLE_PAIRS' if edges else 'NO_COMPATIBLE_PAIR'
|
|
100
|
+
return canonical(certificate['occurrences'])==canonical(endpoints) and canonical(certificate['pairs'])==canonical(edges) and certificate['status']==status
|
|
101
|
+
except (ValueError,TypeError,KeyError,IndexError,AttributeError):return False
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def certify_acquisition_witness(model,measurements,*,max_search_steps=None):
|
|
105
|
+
return _certify_acquisition_witness(model,measurements,max_search_steps=max_search_steps)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def verify_acquisition_witness(model,measurements,certificate,*,max_search_steps=None):
|
|
109
|
+
return _verify_acquisition_witness(model,measurements,certificate,max_search_steps=max_search_steps)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def certify_raw_acquisition_witness(model,measurements,*,max_search_steps=None):
|
|
113
|
+
return _certify_acquisition_witness(model,measurements,max_search_steps=max_search_steps,raw=True)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def verify_raw_acquisition_witness(model,measurements,certificate,*,max_search_steps=None):
|
|
117
|
+
return _verify_acquisition_witness(model,measurements,certificate,max_search_steps=max_search_steps,raw=True)
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Complete shortest supported joint-state paths and expanded NMU lineage."""
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from .identity import encode
|
|
4
|
+
from .acquisition_snapshot import acquisition_snapshot
|
|
5
|
+
from .frame_engine import canonical
|
|
6
|
+
from .observed_actuation_discovery import certify_observed_actuation_discovery
|
|
7
|
+
from .joint_frontier_acquisition import _requests
|
|
8
|
+
from .measured_context_laws import certify_measured_context_laws
|
|
9
|
+
from .role_work import RoleSearchBudget
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _seed_routes(state,budget):
|
|
13
|
+
result={}
|
|
14
|
+
for point in state['points']:
|
|
15
|
+
p=point['port'];occ=point['occurrence'];route=[]
|
|
16
|
+
for i,coord in enumerate(occ['coordinates']):
|
|
17
|
+
budget.consume();route.append({'kind':'observed','domain':'observed','port':p,'source':point['source'],'frame':occ['frame'],'position':i,'coordinate':deepcopy(coord)})
|
|
18
|
+
result[p]=[route]
|
|
19
|
+
return result
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _next_routes(previous,law,step,action,budget):
|
|
23
|
+
routes={};port=law['root_port']
|
|
24
|
+
for candidate in law['candidates']:
|
|
25
|
+
for proof in candidate['structural_response']['proofs']:
|
|
26
|
+
if proof['output']!=law['result']['output']:continue
|
|
27
|
+
for prior in previous:
|
|
28
|
+
route=[]
|
|
29
|
+
for point in proof['characters'][0]:
|
|
30
|
+
budget.consume()
|
|
31
|
+
if point['kind']=='trigger':
|
|
32
|
+
if point['frame']==0:route.append(deepcopy(prior[point['position']]))
|
|
33
|
+
else:route.append({'kind':'action','domain':'query_action','step':step,'action':action,'position':point['position']})
|
|
34
|
+
else:route.append({**deepcopy(point),'domain':'learned','port':port})
|
|
35
|
+
routes[canonical(route)]=route
|
|
36
|
+
for witness in candidate['crystal_paths']:
|
|
37
|
+
route=[]
|
|
38
|
+
for i,coord in enumerate(witness['occurrence']['coordinates']):
|
|
39
|
+
budget.consume();route.append({'kind':'crystal','domain':'learned','port':port,'source':witness['source'],'frame':2,'position':i,'coordinate':deepcopy(coord)})
|
|
40
|
+
routes[canonical(route)]=route
|
|
41
|
+
if not routes:raise ValueError('Resolved law lacks a complete character route')
|
|
42
|
+
return [routes[key] for key in sorted(routes)]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def certify_actuation_goal_frontier(model,groups,measurements,observation,observed_groups,observed_measurements,anchor_group,catalogue,catalogue_measurements,goal,*,max_depth=None,max_search_steps=None):
|
|
46
|
+
budget=RoleSearchBudget(max_search_steps)
|
|
47
|
+
with budget.scope():
|
|
48
|
+
budget.consume()
|
|
49
|
+
if max_depth is not None and (type(max_depth) is not int or max_depth<0):raise ValueError('Depth is None or a nonnegative integer')
|
|
50
|
+
model,observation=acquisition_snapshot(model),acquisition_snapshot(observation)
|
|
51
|
+
groups,measurements,observed_groups,observed_measurements=deepcopy((groups,measurements,observed_groups,observed_measurements))
|
|
52
|
+
discovery=certify_observed_actuation_discovery(model,groups,measurements,observation,observed_groups,observed_measurements,anchor_group,catalogue,catalogue_measurements);state=discovery['state_certificate'];goal=deepcopy(goal)
|
|
53
|
+
if not isinstance(goal,dict) or not goal or not set(goal)<=set(state['ports']):raise ValueError('Nonempty original-interface goal required')
|
|
54
|
+
for value in goal.values():
|
|
55
|
+
if not isinstance(value,str) or not value:raise ValueError('Nonempty raw goal frames required')
|
|
56
|
+
encode(value)
|
|
57
|
+
ready=state['result']['status']=='JOINT_STATE_READY';nodes=[{'state':deepcopy(state['state']),'depth':0,'kind':'OBSERVED_SCOPE_VALUES'}];known={canonical(state['state']):0};edges=[];predecessors={0:[]};frontier=[0] if ready and discovery['result']['catalogue_current'] else [];depth=0;blocked=[];goals=[0] if ready and all(state['state'][p]==v for p,v in goal.items()) else [];found=0 if goals else None
|
|
58
|
+
while frontier and found is None and (max_depth is None or depth<max_depth):
|
|
59
|
+
upcoming=[]
|
|
60
|
+
for source in frontier:
|
|
61
|
+
before=nodes[source]['state']
|
|
62
|
+
for action in discovery['available_actions']:
|
|
63
|
+
budget.consume();laws=[];after={};supported=True
|
|
64
|
+
for port in state['ports']:
|
|
65
|
+
budget.consume();context={p:before[p] for p in state['ports'] if p!=port};law=certify_measured_context_laws(model,groups,measurements,port,before[port],action,context);laws.append({'port':port,'certificate':law})
|
|
66
|
+
if law['result']['status']=='MEASURED_CONTEXT_LAW_RESOLVED':after[port]=law['result']['output'][0]
|
|
67
|
+
else:supported=False
|
|
68
|
+
successor=None;index=len(edges)
|
|
69
|
+
if supported:
|
|
70
|
+
key=canonical(after)
|
|
71
|
+
if key not in known:
|
|
72
|
+
successor=len(nodes);known[key]=successor;nodes.append({'state':after,'depth':depth+1,'kind':'PROJECTED'});predecessors[successor]=[];upcoming.append(successor)
|
|
73
|
+
else:successor=known[key]
|
|
74
|
+
if nodes[successor]['depth']==depth+1:predecessors[successor].append(index)
|
|
75
|
+
if all(after[p]==v for p,v in goal.items()):
|
|
76
|
+
found=depth+1 if found is None else found
|
|
77
|
+
if successor not in goals:goals.append(successor)
|
|
78
|
+
else:blocked.append(index)
|
|
79
|
+
edges.append({'source':source,'action':action,'laws':laws,'successor':successor,'supported':bool(supported)})
|
|
80
|
+
frontier=upcoming;depth+=1
|
|
81
|
+
if blocked:break
|
|
82
|
+
solutions=[]
|
|
83
|
+
for target in sorted(goals):
|
|
84
|
+
pending=[(target,[])]
|
|
85
|
+
while pending:
|
|
86
|
+
budget.consume();node,reverse=pending.pop()
|
|
87
|
+
if node:
|
|
88
|
+
for edge in reversed(predecessors[node]):pending.append((edges[edge]['source'],reverse+[edge]))
|
|
89
|
+
continue
|
|
90
|
+
path=list(reversed(reverse));owners=_seed_routes(state,budget);actions=[]
|
|
91
|
+
for step,edge_index in enumerate(path):
|
|
92
|
+
budget.consume();edge=edges[edge_index];actions.append(edge['action']);next_owners={}
|
|
93
|
+
for item in edge['laws']:next_owners[item['port']]=_next_routes(owners[item['port']],item['certificate'],step,edge['action'],budget)
|
|
94
|
+
owners=next_owners
|
|
95
|
+
solutions.append({'goal_node':target,'edges':path,'actions':actions,'lineage_routes':owners})
|
|
96
|
+
solutions.sort(key=lambda s:(s['actions'],s['edges']))
|
|
97
|
+
graph={'state_certificate':state,'nodes':nodes,'edges':edges,'result':{'blocked_edges':blocked}}
|
|
98
|
+
requests=_requests(graph,budget);choices=[]
|
|
99
|
+
for solution in solutions:choices.append({'kind':'SUPPORTED_GOAL','target':solution['goal_node'],**deepcopy(solution)})
|
|
100
|
+
for request in requests:
|
|
101
|
+
for prefix in request['prefixes']:choices.append({'kind':'FRONTIER_EXPERIENCE','target':request['edge'],'edges':prefix['edges']+[request['edge']],'actions':prefix['actions']+[request['action']],'lineage_routes':deepcopy(prefix['lineage_routes'])})
|
|
102
|
+
for target in frontier:
|
|
103
|
+
if target in goals:continue
|
|
104
|
+
paths=[(target,[])]
|
|
105
|
+
while paths:
|
|
106
|
+
budget.consume();node,reverse=paths.pop()
|
|
107
|
+
if node:
|
|
108
|
+
for edge_index in reversed(predecessors[node]):paths.append((edges[edge_index]['source'],reverse+[edge_index]))
|
|
109
|
+
continue
|
|
110
|
+
path=list(reversed(reverse));owners=_seed_routes(state,budget);actions=[]
|
|
111
|
+
for step,j in enumerate(path):
|
|
112
|
+
budget.consume();edge=edges[j];actions.append(edge['action']);owners={item['port']:_next_routes(owners[item['port']],item['certificate'],step,edge['action'],budget) for item in edge['laws']}
|
|
113
|
+
choices.append({'kind':'SUPPORTED_PREFIX','target':target,'edges':path,'actions':actions,'lineage_routes':owners})
|
|
114
|
+
choices.sort(key=lambda x:(x['kind'],x['target'],x['actions'],x['edges']))
|
|
115
|
+
status='GOAL_ALREADY_OBSERVED' if found==0 else 'OBSERVED_STATE_UNRESOLVED' if not ready else 'CATALOGUE_NOT_CURRENT' if not discovery['result']['catalogue_current'] else 'SUPPORTED_GOAL_READY' if found is not None else 'FRONTIER_EXPERIENCE_READY' if blocked else 'SUPPORTED_FRONTIER_CLOSED' if not frontier else 'DECLARED_DEPTH_REACHED'
|
|
116
|
+
result={'status':status,'shortest_supported_goal_length':found,'goal_nodes':sorted(goals),'blocked_edges':blocked,'frontier':frontier,'depth_reached':depth,'supported_frontier_exhausted':not bool(frontier),'choice_count':len(choices),'request_count':len(requests),'minimum_acquisition_distance':min((r['acquisition_distance'] for r in requests),default=None),'catalogue_current':discovery['result']['catalogue_current']}
|
|
117
|
+
return {'policy':'actuation_goal_frontier_v1','goal':goal,'max_depth':max_depth,'discovery':discovery,'state_certificate':state,'nodes':nodes,'edges':edges,'solutions':solutions,'requests':requests,'choices':choices,'result':result}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""Independent graph coverage, goal paths and correlated character-route check."""
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from .identity import encode
|
|
4
|
+
from .acquisition_snapshot import acquisition_snapshot
|
|
5
|
+
from .frame_engine import canonical
|
|
6
|
+
from .observed_actuation_discovery_check import verify_observed_actuation_discovery
|
|
7
|
+
from .measured_context_laws_check import verify_measured_context_laws
|
|
8
|
+
from .role_work import RoleSearchBudget
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _initial_owners(state,budget):
|
|
12
|
+
owners={}
|
|
13
|
+
for point in state['points']:
|
|
14
|
+
route=[];occ=point['occurrence']
|
|
15
|
+
for i,coordinate in enumerate(occ['coordinates']):
|
|
16
|
+
budget.consume();route.append({'kind':'observed','domain':'observed','port':point['port'],'source':point['source'],'frame':occ['frame'],'position':i,'coordinate':deepcopy(coordinate)})
|
|
17
|
+
owners[point['port']]=[route]
|
|
18
|
+
return owners
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _expanded_owners(priors,law,step,action,budget):
|
|
22
|
+
distinct={};port=law['root_port']
|
|
23
|
+
for family in law['candidates']:
|
|
24
|
+
for proof in family['structural_response']['proofs']:
|
|
25
|
+
if proof['output']!=law['result']['output']:continue
|
|
26
|
+
for prior in priors:
|
|
27
|
+
current=[]
|
|
28
|
+
for point in proof['characters'][0]:
|
|
29
|
+
budget.consume()
|
|
30
|
+
if point['kind']=='crystal':current.append({**deepcopy(point),'domain':'learned','port':port})
|
|
31
|
+
elif point['frame']==0:current.append(deepcopy(prior[point['position']]))
|
|
32
|
+
elif point['frame']==1:current.append({'kind':'action','domain':'query_action','step':step,'action':action,'position':point['position']})
|
|
33
|
+
else:raise ValueError('Invalid original trigger frame')
|
|
34
|
+
distinct[canonical(current)]=current
|
|
35
|
+
for crystal in family['crystal_paths']:
|
|
36
|
+
current=[]
|
|
37
|
+
for position,coordinate in enumerate(crystal['occurrence']['coordinates']):
|
|
38
|
+
budget.consume();current.append({'kind':'crystal','domain':'learned','port':port,'source':crystal['source'],'frame':2,'position':position,'coordinate':deepcopy(coordinate)})
|
|
39
|
+
distinct[canonical(current)]=current
|
|
40
|
+
if not distinct:raise ValueError('Missing lineage route')
|
|
41
|
+
return [distinct[k] for k in sorted(distinct)]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def verify_actuation_goal_frontier(model,groups,measurements,observation,observed_groups,observed_measurements,anchor_group,catalogue,catalogue_measurements,goal,certificate,*,max_depth=None,max_search_steps=None):
|
|
45
|
+
budget=RoleSearchBudget(max_search_steps)
|
|
46
|
+
with budget.scope():
|
|
47
|
+
budget.consume()
|
|
48
|
+
try:
|
|
49
|
+
c=deepcopy(certificate)
|
|
50
|
+
if set(c)!={'policy','goal','max_depth','discovery','state_certificate','nodes','edges','solutions','requests','choices','result'} or c['policy']!='actuation_goal_frontier_v1':return False
|
|
51
|
+
if max_depth is not None and (type(max_depth) is not int or max_depth<0):return False
|
|
52
|
+
if canonical(c['goal'])!=canonical(goal) or type(c['max_depth']) is not type(max_depth) or c['max_depth']!=max_depth:return False
|
|
53
|
+
if any(type(c[key]) is not list for key in ('nodes','edges','solutions')):return False
|
|
54
|
+
model,observation=acquisition_snapshot(model),acquisition_snapshot(observation)
|
|
55
|
+
groups,measurements,observed_groups,observed_measurements=deepcopy((groups,measurements,observed_groups,observed_measurements))
|
|
56
|
+
state=c['state_certificate']
|
|
57
|
+
discovery=c['discovery']
|
|
58
|
+
if not verify_observed_actuation_discovery(model,groups,measurements,observation,observed_groups,observed_measurements,anchor_group,catalogue,catalogue_measurements,discovery) or canonical(state)!=canonical(discovery['state_certificate']):return False
|
|
59
|
+
if not isinstance(goal,dict) or not goal or not set(goal)<=set(state['ports']):return False
|
|
60
|
+
for value in goal.values():
|
|
61
|
+
if not isinstance(value,str) or not value:return False
|
|
62
|
+
encode(value)
|
|
63
|
+
ready=state['result']['status']=='JOINT_STATE_READY';expected_nodes=[{'state':deepcopy(state['state']),'depth':0,'kind':'OBSERVED_SCOPE_VALUES'}];registered={canonical(state['state']):0};parents={0:[]};layer=[0] if ready and discovery['result']['catalogue_current'] else [];level=0;cursor=0;blocked=[];goals=[0] if ready and all(state['state'][p]==v for p,v in goal.items()) else [];found=0 if goals else None
|
|
64
|
+
while layer and found is None and (max_depth is None or level<max_depth):
|
|
65
|
+
following=[]
|
|
66
|
+
for source in layer:
|
|
67
|
+
before=expected_nodes[source]['state']
|
|
68
|
+
for action in discovery['available_actions']:
|
|
69
|
+
budget.consume()
|
|
70
|
+
if cursor>=len(c['edges']):return False
|
|
71
|
+
edge=c['edges'][cursor]
|
|
72
|
+
if set(edge)!={'source','action','laws','successor','supported'} or type(edge['source']) is not int or edge['source']!=source or edge['action']!=action or len(edge['laws'])!=len(state['ports']):return False
|
|
73
|
+
after={};supported=True
|
|
74
|
+
for port,item in zip(state['ports'],edge['laws']):
|
|
75
|
+
budget.consume()
|
|
76
|
+
if set(item)!={'port','certificate'} or item['port']!=port:return False
|
|
77
|
+
context={p:before[p] for p in state['ports'] if p!=port};law=item['certificate']
|
|
78
|
+
if not verify_measured_context_laws(model,groups,measurements,port,before[port],action,context,law):return False
|
|
79
|
+
if law['result']['status']=='MEASURED_CONTEXT_LAW_RESOLVED':after[port]=law['result']['output'][0]
|
|
80
|
+
else:supported=False
|
|
81
|
+
successor=None
|
|
82
|
+
if supported:
|
|
83
|
+
key=canonical(after)
|
|
84
|
+
if key in registered:successor=registered[key]
|
|
85
|
+
else:
|
|
86
|
+
successor=len(expected_nodes);registered[key]=successor;expected_nodes.append({'state':after,'depth':level+1,'kind':'PROJECTED'});parents[successor]=[];following.append(successor)
|
|
87
|
+
if expected_nodes[successor]['depth']==level+1:parents[successor].append(cursor)
|
|
88
|
+
if all(after[p]==v for p,v in goal.items()):
|
|
89
|
+
found=level+1 if found is None else found
|
|
90
|
+
if successor not in goals:goals.append(successor)
|
|
91
|
+
else:blocked.append(cursor)
|
|
92
|
+
if type(edge['supported']) is not bool or edge['supported']!=supported or (successor is not None and type(edge['successor']) is not int) or edge['successor']!=successor:return False
|
|
93
|
+
cursor+=1
|
|
94
|
+
layer=following;level+=1
|
|
95
|
+
if blocked:break
|
|
96
|
+
if len(c['edges'])!=cursor or canonical(c['nodes'])!=canonical(expected_nodes):return False
|
|
97
|
+
expected_solutions=[]
|
|
98
|
+
for target in sorted(goals):
|
|
99
|
+
stack=[(target,[])]
|
|
100
|
+
while stack:
|
|
101
|
+
budget.consume();node,reverse=stack.pop()
|
|
102
|
+
if node!=0:
|
|
103
|
+
for edge_index in reversed(parents[node]):stack.append((c['edges'][edge_index]['source'],reverse+[edge_index]))
|
|
104
|
+
continue
|
|
105
|
+
path=list(reversed(reverse));owners=_initial_owners(state,budget);actions=[]
|
|
106
|
+
for step,edge_index in enumerate(path):
|
|
107
|
+
budget.consume();edge=c['edges'][edge_index];actions.append(edge['action']);updated={}
|
|
108
|
+
for item in edge['laws']:updated[item['port']]=_expanded_owners(owners[item['port']],item['certificate'],step,edge['action'],budget)
|
|
109
|
+
owners=updated
|
|
110
|
+
expected_solutions.append({'goal_node':target,'edges':path,'actions':actions,'lineage_routes':owners})
|
|
111
|
+
expected_solutions.sort(key=lambda s:(s['actions'],s['edges']))
|
|
112
|
+
if canonical(c['solutions'])!=canonical(expected_solutions):return False
|
|
113
|
+
requests=[]
|
|
114
|
+
for index in blocked:
|
|
115
|
+
edge=c['edges'][index];paths=[];stack=[(edge['source'],[])]
|
|
116
|
+
while stack:
|
|
117
|
+
budget.consume();node,reverse=stack.pop()
|
|
118
|
+
if node:
|
|
119
|
+
for parent in reversed(parents[node]):stack.append((c['edges'][parent]['source'],reverse+[parent]))
|
|
120
|
+
continue
|
|
121
|
+
path=list(reversed(reverse));owners=_initial_owners(state,budget);actions=[]
|
|
122
|
+
for step,j in enumerate(path):
|
|
123
|
+
budget.consume();e=c['edges'][j];actions.append(e['action']);owners={item['port']:_expanded_owners(owners[item['port']],item['certificate'],step,e['action'],budget) for item in e['laws']}
|
|
124
|
+
paths.append({'edges':path,'actions':actions,'lineage_routes':owners})
|
|
125
|
+
paths.sort(key=lambda p:(p['actions'],p['edges']));requests.append({'edge':index,'source':edge['source'],'action':edge['action'],'before':deepcopy(expected_nodes[edge['source']]['state']),'acquisition_distance':expected_nodes[edge['source']]['depth']+1,'unresolved_ports':[item['port'] for item in edge['laws'] if item['certificate']['result']['status']!='MEASURED_CONTEXT_LAW_RESOLVED'],'prefixes':paths})
|
|
126
|
+
choices=[]
|
|
127
|
+
for solution in expected_solutions:choices.append({'kind':'SUPPORTED_GOAL','target':solution['goal_node'],**deepcopy(solution)})
|
|
128
|
+
for request in requests:
|
|
129
|
+
for prefix in request['prefixes']:choices.append({'kind':'FRONTIER_EXPERIENCE','target':request['edge'],'edges':prefix['edges']+[request['edge']],'actions':prefix['actions']+[request['action']],'lineage_routes':deepcopy(prefix['lineage_routes'])})
|
|
130
|
+
for target in layer:
|
|
131
|
+
if target in goals:continue
|
|
132
|
+
pending=[(target,[])]
|
|
133
|
+
while pending:
|
|
134
|
+
budget.consume();node,reverse=pending.pop()
|
|
135
|
+
if node:
|
|
136
|
+
for parent in reversed(parents[node]):pending.append((c['edges'][parent]['source'],reverse+[parent]))
|
|
137
|
+
continue
|
|
138
|
+
path=list(reversed(reverse));owners=_initial_owners(state,budget);actions=[]
|
|
139
|
+
for step,j in enumerate(path):
|
|
140
|
+
budget.consume();edge=c['edges'][j];actions.append(edge['action']);owners={item['port']:_expanded_owners(owners[item['port']],item['certificate'],step,edge['action'],budget) for item in edge['laws']}
|
|
141
|
+
choices.append({'kind':'SUPPORTED_PREFIX','target':target,'edges':path,'actions':actions,'lineage_routes':owners})
|
|
142
|
+
choices.sort(key=lambda x:(x['kind'],x['target'],x['actions'],x['edges']))
|
|
143
|
+
if canonical(c['requests'])!=canonical(requests) or canonical(c['choices'])!=canonical(choices):return False
|
|
144
|
+
status='GOAL_ALREADY_OBSERVED' if found==0 else 'OBSERVED_STATE_UNRESOLVED' if not ready else 'CATALOGUE_NOT_CURRENT' if not discovery['result']['catalogue_current'] else 'SUPPORTED_GOAL_READY' if found is not None else 'FRONTIER_EXPERIENCE_READY' if blocked else 'SUPPORTED_FRONTIER_CLOSED' if not layer else 'DECLARED_DEPTH_REACHED'
|
|
145
|
+
result={'status':status,'shortest_supported_goal_length':found,'goal_nodes':sorted(goals),'blocked_edges':blocked,'frontier':layer,'depth_reached':level,'supported_frontier_exhausted':not bool(layer),'choice_count':len(choices),'request_count':len(requests),'minimum_acquisition_distance':min((r['acquisition_distance'] for r in requests),default=None),'catalogue_current':discovery['result']['catalogue_current']}
|
|
146
|
+
return canonical(c['result'])==canonical(result)
|
|
147
|
+
except (ValueError,TypeError,KeyError,IndexError,AttributeError):return False
|