cooptools 1.62__tar.gz → 1.63__tar.gz
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.
- {cooptools-1.62 → cooptools-1.63}/PKG-INFO +1 -1
- {cooptools-1.62 → cooptools-1.63}/cooptools/graphs/graph.py +205 -22
- {cooptools-1.62 → cooptools-1.63}/cooptools.egg-info/PKG-INFO +1 -1
- {cooptools-1.62 → cooptools-1.63}/setup.py +1 -1
- {cooptools-1.62 → cooptools-1.63}/MANIFEST.in +0 -0
- {cooptools-1.62 → cooptools-1.63}/README.md +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/anchor.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/asyncable.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/cli/CliAtomicUserInteraction.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/cli/CliMenu.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/cli/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/cli/fileContentReturn.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/cnxn_info.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/colors.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/commandDesignPattern/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/commandDesignPattern/commandController.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/commandDesignPattern/commandProtocol.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/commandDesignPattern/exceptions.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/common.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/config.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/coopDataclass.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/coopEnum.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/coopthreading.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/currency.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/dataRefresher/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/dataRefresher/dataHub.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/dataRefresher/dataRefresher.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/dataStore/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/dataStore/dataProcessor.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/dataStore/dataStoreProtocol.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/dataStore/dbConnectionURI.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/dataStore/inMemoryDataStore.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/date_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/decay.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/decor.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/dictPolicies.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/exceptions.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/expertise/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/expertise/expertiseArgs.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/expertise/expertiseSchedules.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/finance/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/finance/dicounted_cashflow_analysis.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/finance/fund_projection.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/finance/fund_projection_renderer.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/finance/futureValueProjector.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/finance/growth_projections.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/finance/reports.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/finance/utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/geometry_utils/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/geometry_utils/circle_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/geometry_utils/common.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/geometry_utils/curve_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/geometry_utils/line_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/geometry_utils/polygon_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/geometry_utils/rect_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/geometry_utils/triangle_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/geometry_utils/vector_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/graphs/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/graphs/astar_results_viewer.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/graphs/draw.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/graphs/graph_dcs.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/graphs/graph_definitions.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/graphs/utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/actionItemTracker/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/actionItemTracker/ai_tracker.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/actionItemTracker/dcs.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/discreteEventSimulator/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/discreteEventSimulator/discreteEventSimulator.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/jsonIO.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/metrics.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/triggerActionSystem/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/triggerActionSystem/signal.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/ideas/triggerActionSystem/trigger.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/loggingHelpers.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/marchingSquares.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/materialHandling/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/materialHandling/cli.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/materialHandling/dcs.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/materialHandling/selectionCriteria.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/matrixManipulation.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/os_manip.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/pandasHelpers.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/physics/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/physics/kinematic.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/physics/kinematic_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/physics/movement.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/physics/trajectory.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/physics/waypoint.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/physics/waypointFollower.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/plotting.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/printing.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/protocols.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/qualifiers/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/qualifiers/cli.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/qualifiers/qualifier.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/randoms.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/register.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/reservation/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/reservation/dcs.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/reservation/enums.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/reservation/reservationmanager.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/retry.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/sectors/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/sectors/grids/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/sectors/grids/gridState.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/sectors/grids/grid_base.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/sectors/grids/hexGrid.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/sectors/grids/rectGrid.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/sectors/hex_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/sectors/sect_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/sectors/sectorTree/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/sectors/sectorTree/sectorTree.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/statistics/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/statistics/activityReport.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/statistics/controlChart/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/statistics/controlChart/controlChart.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/statistics/controlChart/plotting.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/statistics/oee/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/statistics/oee/oeeHub.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/taskProcessing/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/taskProcessing/dcs.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/taskProcessing/taskProcessor.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/timeTracker/__init__.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/timeTracker/decay.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/timeTracker/timeTracker.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/timeWindow.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/toggles.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/transform.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/trends.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/typeProviders.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/typevalidation.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools/version.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools.egg-info/SOURCES.txt +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools.egg-info/dependency_links.txt +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools.egg-info/not-zip-safe +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools.egg-info/requires.txt +0 -0
- {cooptools-1.62 → cooptools-1.63}/cooptools.egg-info/top_level.txt +0 -0
- {cooptools-1.62 → cooptools-1.63}/requirements.txt +0 -0
- {cooptools-1.62 → cooptools-1.63}/setup.cfg +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_CliAtomicUserInteraction.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_asyncable.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_cdp_bugs.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_commandDesignPattern.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_common.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_config.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_coopEnum.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_currency.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_date_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_fund_projection.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_os_manip.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_pandas.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_printing.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_qualifiers.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_sectors.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_sectors_hex.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_sectors_sectorTree.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_statistics.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_tasks.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_toggles.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_trends.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_typevalidation.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_vector_utils.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/test_version.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/tests_graph.py +0 -0
- {cooptools-1.62 → cooptools-1.63}/tests/tests_gridsystem.py +0 -0
|
@@ -673,16 +673,9 @@ class Graph(object):
|
|
|
673
673
|
if e_in: msg += f" the end \'{end.name}\' is in the disabled_node_ids"
|
|
674
674
|
raise Exception(msg)
|
|
675
675
|
|
|
676
|
-
for x in disabled_node_ids:
|
|
677
|
-
self.disable_edges_to_node(
|
|
678
|
-
node=self.node_by_name(node_name=x),
|
|
679
|
-
disabler=INTERNAL_DISABLER
|
|
680
|
-
)
|
|
681
|
-
|
|
682
676
|
if not ignored_disablers:
|
|
683
677
|
ignored_disablers = []
|
|
684
678
|
|
|
685
|
-
"""Returns a list of nodes as a path from the given start to the given end in the given graph"""
|
|
686
679
|
logger.debug(f"Performing A* over map of length: {len(self._graph_dict)}")
|
|
687
680
|
|
|
688
681
|
# Create start and end node
|
|
@@ -695,9 +688,11 @@ class Graph(object):
|
|
|
695
688
|
open_set = set()
|
|
696
689
|
closed_set = set()
|
|
697
690
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
691
|
+
# Check reachability: any enabled edge into end whose source isn't disabled
|
|
692
|
+
connections_to_end = self.edges_to_node(end, only_enabled=True, ignored_disablers=ignored_disablers)
|
|
693
|
+
if disabled_node_ids is not None:
|
|
694
|
+
connections_to_end = [e for e in connections_to_end if e.start.name not in disabled_node_ids]
|
|
695
|
+
if len(connections_to_end) != 0:
|
|
701
696
|
open_set.add(start_iter)
|
|
702
697
|
|
|
703
698
|
cc = -1
|
|
@@ -742,12 +737,15 @@ class Graph(object):
|
|
|
742
737
|
steps,
|
|
743
738
|
source=start,
|
|
744
739
|
dest=end,
|
|
745
|
-
disabled_node_ids=list(disabled_node_ids) if disabled_node_ids is not None else None)
|
|
740
|
+
disabled_node_ids=list(disabled_node_ids) if disabled_node_ids is not None else None)
|
|
746
741
|
break
|
|
747
742
|
|
|
748
743
|
# Generate children
|
|
749
744
|
for new_node in self._graph_dict[current_item.graph_node]: # Adjacent nodes
|
|
750
|
-
#
|
|
745
|
+
# Skip nodes excluded by the caller — checked inline to avoid mutating the graph
|
|
746
|
+
if disabled_node_ids is not None and new_node.name in disabled_node_ids:
|
|
747
|
+
continue
|
|
748
|
+
|
|
751
749
|
edges = self.edges_between(
|
|
752
750
|
nodeA=current_item.graph_node,
|
|
753
751
|
nodeB=new_node
|
|
@@ -758,8 +756,8 @@ class Graph(object):
|
|
|
758
756
|
if len(enabled_edges) == 0:
|
|
759
757
|
continue
|
|
760
758
|
|
|
761
|
-
# find the min-
|
|
762
|
-
enabled_edges.sort(key=lambda x: x.
|
|
759
|
+
# find the min-cost edge
|
|
760
|
+
enabled_edges.sort(key=lambda x: x.cost)
|
|
763
761
|
min_edge = enabled_edges[0]
|
|
764
762
|
|
|
765
763
|
new_item = AStarMetrics(current_item, new_node, min_edge)
|
|
@@ -797,17 +795,9 @@ class Graph(object):
|
|
|
797
795
|
failure_reason=failure_reason,
|
|
798
796
|
)
|
|
799
797
|
else:
|
|
800
|
-
''' Log Path found '''
|
|
801
798
|
logger.debug(f"Path found from [{start}] to [{end}] in {len(steps)} steps")
|
|
802
799
|
ret = results
|
|
803
800
|
|
|
804
|
-
if disabled_node_ids is not None:
|
|
805
|
-
for x in disabled_node_ids:
|
|
806
|
-
self.enable_edges_to_node(
|
|
807
|
-
node=self.node_by_name(node_name=x),
|
|
808
|
-
disabler=INTERNAL_DISABLER
|
|
809
|
-
)
|
|
810
|
-
|
|
811
801
|
return ret
|
|
812
802
|
|
|
813
803
|
def path_length(self, path:List[Node]):
|
|
@@ -1041,6 +1031,199 @@ class Graph(object):
|
|
|
1041
1031
|
branches_graph_dict.pop(src, None)
|
|
1042
1032
|
return Graph(branches_graph_dict), steps
|
|
1043
1033
|
|
|
1034
|
+
def greedy_target_seek(self,
|
|
1035
|
+
sources: Iterable[Node],
|
|
1036
|
+
targets: Iterable[Node],
|
|
1037
|
+
disabled_node_ids: frozenset[str] = None) -> Tuple[Self, list[dict]]:
|
|
1038
|
+
"""Grow a spanning tree from sources toward all targets using greedy path commitment.
|
|
1039
|
+
|
|
1040
|
+
Unlike branching_target_seek (which advances one hop per outer iteration),
|
|
1041
|
+
this function advances each frontier along its full planned A* path until it
|
|
1042
|
+
collides with a node already committed to the tree. Cheaper paths commit
|
|
1043
|
+
first, so shared trunk segments are claimed before branches check for
|
|
1044
|
+
collisions — this produces the correct branching topology in O(branch_depth)
|
|
1045
|
+
outer iterations instead of O(max_path_length).
|
|
1046
|
+
|
|
1047
|
+
Returns:
|
|
1048
|
+
Tuple of (Graph, steps) mirroring branching_target_seek's interface.
|
|
1049
|
+
"""
|
|
1050
|
+
if disabled_node_ids is not None:
|
|
1051
|
+
for x in disabled_node_ids:
|
|
1052
|
+
self.disable_edges_to_node(
|
|
1053
|
+
node=self.node_by_name(node_name=x),
|
|
1054
|
+
disabler=INTERNAL_DISABLER
|
|
1055
|
+
)
|
|
1056
|
+
|
|
1057
|
+
source_set: set[Node] = set(sources)
|
|
1058
|
+
active_nodes: set[Node] = set(sources)
|
|
1059
|
+
current_targets: set[Node] = set(targets)
|
|
1060
|
+
branches_graph_dict: Dict[Node, list] = {x: [] for x in sources}
|
|
1061
|
+
in_tree: set[Node] = set(sources)
|
|
1062
|
+
parent_map: Dict[Node, Node] = {}
|
|
1063
|
+
reached_targets: set[Node] = set()
|
|
1064
|
+
|
|
1065
|
+
steps: list[dict] = []
|
|
1066
|
+
|
|
1067
|
+
def _snap(label, new_edges=None, best_routes=None, pruned=None):
|
|
1068
|
+
steps.append({
|
|
1069
|
+
"label": label,
|
|
1070
|
+
"active": frozenset(active_nodes),
|
|
1071
|
+
"targets": frozenset(current_targets),
|
|
1072
|
+
"in_tree": frozenset(in_tree),
|
|
1073
|
+
"branches": {k: list(v) for k, v in branches_graph_dict.items()},
|
|
1074
|
+
"new_edges": list(new_edges or []),
|
|
1075
|
+
"best_routes": list(best_routes or []),
|
|
1076
|
+
"pruned": list(pruned or []),
|
|
1077
|
+
})
|
|
1078
|
+
|
|
1079
|
+
_snap("Initial state")
|
|
1080
|
+
|
|
1081
|
+
while len(current_targets) > 0:
|
|
1082
|
+
target_nearest: Dict[Node, AStarResults] = {}
|
|
1083
|
+
|
|
1084
|
+
# Find the best full A* path from any active node to each target
|
|
1085
|
+
for node in active_nodes:
|
|
1086
|
+
for target in current_targets:
|
|
1087
|
+
route = self.astar(start=node, end=target)
|
|
1088
|
+
target_nearest.setdefault(target, None)
|
|
1089
|
+
if route.nodes is not None and len(route.nodes) > 0 and (
|
|
1090
|
+
target_nearest.get(target) is None or
|
|
1091
|
+
route.Cost < target_nearest[target].Cost
|
|
1092
|
+
):
|
|
1093
|
+
target_nearest[target] = route
|
|
1094
|
+
|
|
1095
|
+
# Discard targets with no reachable path
|
|
1096
|
+
for target in list(current_targets):
|
|
1097
|
+
route = target_nearest.get(target)
|
|
1098
|
+
if route is None or not route.nodes or len(route.nodes) < 2:
|
|
1099
|
+
current_targets.discard(target)
|
|
1100
|
+
|
|
1101
|
+
if not current_targets:
|
|
1102
|
+
break
|
|
1103
|
+
|
|
1104
|
+
best_routes_display = [
|
|
1105
|
+
list(r.nodes) for r in target_nearest.values()
|
|
1106
|
+
if r is not None and r.nodes is not None and len(r.nodes) > 0
|
|
1107
|
+
]
|
|
1108
|
+
_snap("Routes found", best_routes=best_routes_display)
|
|
1109
|
+
|
|
1110
|
+
# Identify which active nodes hold at least one best route this iteration
|
|
1111
|
+
contributing: set[Node] = set()
|
|
1112
|
+
for target, route in target_nearest.items():
|
|
1113
|
+
if target in current_targets and route is not None and route.nodes:
|
|
1114
|
+
contributing.add(list(route.nodes)[0])
|
|
1115
|
+
|
|
1116
|
+
# Prune dominated active nodes back to the last branch.
|
|
1117
|
+
# Reached targets are exempt — they stay active so the tree can
|
|
1118
|
+
# extend through them toward further targets.
|
|
1119
|
+
pruned_this_step: list[Node] = []
|
|
1120
|
+
dominated = active_nodes - contributing - reached_targets
|
|
1121
|
+
for dominated_node in dominated:
|
|
1122
|
+
current = dominated_node
|
|
1123
|
+
while current not in source_set:
|
|
1124
|
+
parent = parent_map.get(current)
|
|
1125
|
+
active_nodes.discard(current)
|
|
1126
|
+
in_tree.discard(current)
|
|
1127
|
+
branches_graph_dict.pop(current, None)
|
|
1128
|
+
parent_map.pop(current, None)
|
|
1129
|
+
if parent is not None:
|
|
1130
|
+
children = branches_graph_dict.get(parent, [])
|
|
1131
|
+
if current in children:
|
|
1132
|
+
children.remove(current)
|
|
1133
|
+
pruned_this_step.append(current)
|
|
1134
|
+
if parent is None or parent in source_set:
|
|
1135
|
+
break
|
|
1136
|
+
if branches_graph_dict.get(parent, []):
|
|
1137
|
+
break
|
|
1138
|
+
if parent in contributing:
|
|
1139
|
+
active_nodes.add(parent)
|
|
1140
|
+
break
|
|
1141
|
+
current = parent
|
|
1142
|
+
|
|
1143
|
+
if pruned_this_step:
|
|
1144
|
+
_snap("Pruned dominated nodes", pruned=pruned_this_step)
|
|
1145
|
+
|
|
1146
|
+
# Advance each frontier along its full planned path until it collides
|
|
1147
|
+
# with a node already in the tree. Cheaper paths commit first.
|
|
1148
|
+
reachable = [
|
|
1149
|
+
(t, r) for t, r in target_nearest.items()
|
|
1150
|
+
if t in current_targets and r is not None and r.nodes and len(r.nodes) >= 2
|
|
1151
|
+
]
|
|
1152
|
+
reachable.sort(key=lambda x: x[1].Cost)
|
|
1153
|
+
|
|
1154
|
+
new_edges: list[tuple[Node, Node]] = []
|
|
1155
|
+
|
|
1156
|
+
for target, best_route in reachable:
|
|
1157
|
+
if target not in current_targets:
|
|
1158
|
+
continue
|
|
1159
|
+
|
|
1160
|
+
path_nodes = list(best_route.nodes)
|
|
1161
|
+
from_node = path_nodes[0]
|
|
1162
|
+
active_nodes.discard(from_node)
|
|
1163
|
+
|
|
1164
|
+
prev = from_node
|
|
1165
|
+
new_frontier = from_node
|
|
1166
|
+
left_shared_prefix = False
|
|
1167
|
+
|
|
1168
|
+
for node in path_nodes[1:]:
|
|
1169
|
+
if node in in_tree:
|
|
1170
|
+
if not left_shared_prefix:
|
|
1171
|
+
# Fast-forward through the shared trunk without committing.
|
|
1172
|
+
# The trunk is already in the tree; we just find where our
|
|
1173
|
+
# path diverges from it.
|
|
1174
|
+
prev = node
|
|
1175
|
+
new_frontier = node
|
|
1176
|
+
else:
|
|
1177
|
+
# Our new branch segment reconnects to an existing tree node
|
|
1178
|
+
# (confluence / tributary join). Wire it in and stop.
|
|
1179
|
+
branches_graph_dict.setdefault(prev, [])
|
|
1180
|
+
if node not in branches_graph_dict[prev]:
|
|
1181
|
+
branches_graph_dict[prev].append(node)
|
|
1182
|
+
new_frontier = node
|
|
1183
|
+
break
|
|
1184
|
+
else:
|
|
1185
|
+
left_shared_prefix = True
|
|
1186
|
+
branches_graph_dict.setdefault(prev, [])
|
|
1187
|
+
if node not in branches_graph_dict[prev]:
|
|
1188
|
+
branches_graph_dict[prev].append(node)
|
|
1189
|
+
branches_graph_dict.setdefault(node, [])
|
|
1190
|
+
in_tree.add(node)
|
|
1191
|
+
parent_map[node] = prev
|
|
1192
|
+
new_edges.append((prev, node))
|
|
1193
|
+
prev = node
|
|
1194
|
+
new_frontier = node
|
|
1195
|
+
if node == target:
|
|
1196
|
+
break
|
|
1197
|
+
|
|
1198
|
+
active_nodes.add(new_frontier)
|
|
1199
|
+
|
|
1200
|
+
if new_frontier == target or new_frontier in current_targets:
|
|
1201
|
+
current_targets.discard(new_frontier)
|
|
1202
|
+
current_targets.discard(target)
|
|
1203
|
+
reached_targets.add(new_frontier)
|
|
1204
|
+
|
|
1205
|
+
# Post-commit sweep: a path's walk may have passed through another target's
|
|
1206
|
+
# node en route to its own target. Mark any such targets as reached now.
|
|
1207
|
+
for t in list(current_targets):
|
|
1208
|
+
if t in in_tree:
|
|
1209
|
+
current_targets.discard(t)
|
|
1210
|
+
reached_targets.add(t)
|
|
1211
|
+
active_nodes.discard(t)
|
|
1212
|
+
|
|
1213
|
+
_snap("Edges added", new_edges=new_edges, best_routes=best_routes_display)
|
|
1214
|
+
|
|
1215
|
+
if disabled_node_ids is not None:
|
|
1216
|
+
for x in disabled_node_ids:
|
|
1217
|
+
self.enable_edges_to_node(
|
|
1218
|
+
node=self.node_by_name(node_name=x),
|
|
1219
|
+
disabler=INTERNAL_DISABLER
|
|
1220
|
+
)
|
|
1221
|
+
|
|
1222
|
+
for src in list(source_set):
|
|
1223
|
+
if branches_graph_dict.get(src) == []:
|
|
1224
|
+
branches_graph_dict.pop(src, None)
|
|
1225
|
+
return Graph(branches_graph_dict), steps
|
|
1226
|
+
|
|
1044
1227
|
@property
|
|
1045
1228
|
def SectorGraph(self) -> Self:
|
|
1046
1229
|
client_mappings = self._sec_tree.ClientMappings
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cooptools-1.62 → cooptools-1.63}/cooptools/ideas/discreteEventSimulator/discreteEventSimulator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|