diff --git a/ngraph/failure_manager.py b/ngraph/failure_manager.py new file mode 100644 index 0000000..860e560 --- /dev/null +++ b/ngraph/failure_manager.py @@ -0,0 +1,192 @@ +from __future__ import annotations + +import copy +import statistics +from collections import defaultdict +from concurrent.futures import ThreadPoolExecutor, as_completed +from typing import List, Dict, Optional, Tuple, Any + +from ngraph.network import Network +from ngraph.traffic_demand import TrafficDemand +from ngraph.traffic_manager import TrafficManager, TrafficResult +from ngraph.failure_policy import FailurePolicy + + +class FailureManager: + """ + Applies FailurePolicy to a Network, runs traffic placement, and (optionally) + repeats multiple times for Monte Carlo experiments. + + Attributes: + network (Network): The underlying network to mutate (enable/disable nodes/links). + traffic_demands (List[TrafficDemand]): List of demands to place after failures. + failure_policy (Optional[FailurePolicy]): The policy describing what fails. + default_flow_policy_config: The default flow policy for any demands lacking one. + """ + + def __init__( + self, + network: Network, + traffic_demands: List[TrafficDemand], + failure_policy: Optional[FailurePolicy] = None, + default_flow_policy_config=None, + ) -> None: + """ + Initialize a FailureManager. + + Args: + network: The Network to be modified by failures. + traffic_demands: Demands to place on the network after applying failures. + failure_policy: A FailurePolicy specifying the rules of what fails. + default_flow_policy_config: Default FlowPolicyConfig if demands do not specify one. + """ + self.network = network + self.traffic_demands = traffic_demands + self.failure_policy = failure_policy + self.default_flow_policy_config = default_flow_policy_config + + def apply_failures(self) -> None: + """ + Apply the current failure_policy to self.network (in-place). + + If failure_policy is None, this method does nothing. + """ + if not self.failure_policy: + return + + # Collect node/links as dicts {id: attrs}, matching FailurePolicy expectations + node_map = {n_name: n.attrs for n_name, n in self.network.nodes.items()} + link_map = {l_id: l.attrs for l_id, l in self.network.links.items()} + + failed_ids = self.failure_policy.apply_failures(node_map, link_map) + + # Disable the failed entities + for f_id in failed_ids: + if f_id in self.network.nodes: + self.network.disable_node(f_id) + elif f_id in self.network.links: + self.network.disable_link(f_id) + + def run_single_failure_scenario(self) -> List[TrafficResult]: + """ + Applies failures to the network, places the demands, and returns per-demand results. + + Returns: + List[TrafficResult]: A list of traffic result objects under the applied failures. + """ + # Ensure we start with a fully enabled network (in case of reuse) + self.network.enable_all() + + # Apply the current failure policy + self.apply_failures() + + # Build TrafficManager and place demands + tmgr = TrafficManager( + network=self.network, + traffic_demands=copy.deepcopy(self.traffic_demands), + default_flow_policy_config=self.default_flow_policy_config, + ) + tmgr.build_graph() + tmgr.expand_demands() + tmgr.place_all_demands() + + # Return detailed traffic results + return tmgr.get_traffic_results(detailed=True) + + def run_monte_carlo_failures( + self, + iterations: int, + parallelism: int = 1, + ) -> Dict[str, Any]: + """ + Repeatedly applies (randomized) failures to the network and accumulates + per-run traffic data. Returns both overall volume statistics and a + breakdown of results for each (src, dst, priority). + + Args: + iterations (int): Number of times to run the failure scenario. + parallelism (int): Max number of worker threads to use (for parallel runs). + + Returns: + Dict[str, Any]: A dictionary containing: + { + "overall_stats": { + "mean": , + "stdev": , + "min": , + "max": + }, + "by_src_dst": { + (src, dst, priority): [ + { + "iteration": , + "total_volume": , + "placed_volume": , + "unplaced_volume": + }, + ... + ], + ... + } + } + """ + # scenario_list will hold the list of traffic-results (List[TrafficResult]) per iteration + scenario_list: List[List[TrafficResult]] = [] + + # Run in parallel or synchronously + if parallelism > 1: + with ThreadPoolExecutor(max_workers=parallelism) as executor: + futures = [ + executor.submit(self.run_single_failure_scenario) + for _ in range(iterations) + ] + for f in as_completed(futures): + scenario_list.append(f.result()) + else: + for _ in range(iterations): + scenario_list.append(self.run_single_failure_scenario()) + + # If no scenarios were run, return zeroed stats + if not scenario_list: + return { + "overall_stats": {"mean": 0.0, "stdev": 0.0, "min": 0.0, "max": 0.0}, + "by_src_dst": {}, + } + + # Accumulate total placed volumes for each iteration (for top-level summary) + placed_totals: List[float] = [] + + # Dictionary mapping (src, dst, priority) -> list of run-by-run results + by_src_dst: Dict[Tuple[str, str, int], List[Dict[str, float]]] = defaultdict( + list + ) + + for i, traffic_results in enumerate(scenario_list): + # Compute total placed volume for this iteration + scenario_placed_total = sum(r.placed_volume for r in traffic_results) + placed_totals.append(scenario_placed_total) + + # Accumulate detailed data for each (src, dst, priority) + for r in traffic_results: + key = (r.src, r.dst, r.priority) + by_src_dst[key].append( + { + "iteration": i, + "total_volume": r.total_volume, + "placed_volume": r.placed_volume, + "unplaced_volume": r.unplaced_volume, + } + ) + + # Compute overall statistics on the total placed volumes + overall_stats = { + "mean": statistics.mean(placed_totals), + "stdev": statistics.pstdev(placed_totals), + "min": min(placed_totals), + "max": max(placed_totals), + } + + return { + "overall_stats": overall_stats, + "by_src_dst": dict(by_src_dst), + } diff --git a/ngraph/failure_policy.py b/ngraph/failure_policy.py index 302550b..a7f330c 100644 --- a/ngraph/failure_policy.py +++ b/ngraph/failure_policy.py @@ -8,7 +8,7 @@ class FailureCondition: """ A single condition for matching an entity's attribute with an operator and value. - Example usage: + Example usage (YAML-ish): .. code-block:: yaml @@ -17,17 +17,18 @@ class FailureCondition: operator: "<" value: 100 - :param attr: - The name of the attribute to inspect, e.g. "type", "capacity". - :param operator: - The comparison operator: "==", "!=", "<", "<=", ">", ">=". - :param value: - The value to compare against, e.g. "node", 100, True, etc. + Attributes: + attr (str): + The name of the attribute to inspect (e.g. "type", "capacity"). + operator (str): + The comparison operator: "==", "!=", "<", "<=", ">", ">=". + value (Any): + The value to compare against (e.g. "node", 100, True, etc.). """ - attr: str # e.g. "type", "capacity", "region" - operator: str # "==", "!=", "<", "<=", ">", ">=" - value: Any # e.g. "node", 100, "east_coast" + attr: str + operator: str + value: Any @dataclass @@ -35,28 +36,33 @@ class FailureRule: """ A single rule defining how to match entities and then select them for failure. - - conditions: list of conditions - - logic: how to combine conditions ("and", "or", "any") - - rule_type: how to pick from matched entities ("random", "choice", "all") - - probability: used by "random" (a float in [0,1]) - - count: used by "choice" (e.g. pick 2) - - :param conditions: - A list of :class:`FailureCondition` to filter matching entities. - :param logic: - How to combine the conditions for matching: "and", "or", or "any". - - "and": all conditions must be true - - "or": at least one condition is true - - "any": skip condition checks; everything is matched - :param rule_type: - The selection strategy. One of: - - "random": pick each matched entity with `probability` - - "choice": pick exactly `count` from matched - - "all": pick all matched - :param probability: - Probability of selecting any matched entity (used only if rule_type="random"). - :param count: - Number of matched entities to pick (used only if rule_type="choice"). + * conditions: list of conditions + * logic: how to combine conditions ("and", "or", "any") + * rule_type: how to pick from matched entities ("random", "choice", "all") + * probability: used by "random" (a float in [0,1]) + * count: used by "choice" (e.g. pick 2) + + When multiple FailureRules appear in a FailurePolicy, the final + set of failures is the **union** of all entities selected by each rule. + + Attributes: + conditions (List[FailureCondition]): + A list of conditions to filter matching entities. + logic (Literal["and", "or", "any"]): + - "and": All conditions must be true. + - "or": At least one condition is true. + - "any": Skip condition checks; everything is matched. + rule_type (Literal["random", "choice", "all"]): + The selection strategy among the matched set: + - "random": Each matched entity is chosen independently + with probability = `probability`. + - "choice": Pick exactly `count` items from the matched set + (randomly sampled). + - "all": Select every matched entity. + probability (float): + Probability in [0,1], used only if `rule_type="random"`. + count (int): + Number of matched entities to pick, used only if `rule_type="choice"`. """ conditions: List[FailureCondition] = field(default_factory=list) @@ -65,6 +71,16 @@ class FailureRule: probability: float = 1.0 count: int = 1 + def __post_init__(self) -> None: + """ + Validate certain fields after initialization. + """ + if self.rule_type == "random": + if not (0.0 <= self.probability <= 1.0): + raise ValueError( + f"probability={self.probability} must be within [0,1] for rule_type='random'." + ) + @dataclass class FailurePolicy: @@ -72,42 +88,42 @@ class FailurePolicy: A container for multiple FailureRules and arbitrary metadata in `attrs`. The method :meth:`apply_failures` merges nodes and links into a single - dictionary (by their unique ID), and then applies each rule in turn, - building a union of all failed entities. - - :param rules: - A list of :class:`FailureRule` objects to apply. - :param attrs: - A dictionary for storing policy-wide metadata (e.g. "name", "description"). + dictionary (by their unique ID), then applies each rule in turn. The final + result is the union of all failures from each rule. + + Attributes: + rules (List[FailureRule]): + A list of FailureRules to apply. + attrs (Dict[str, Any]): + Arbitrary metadata about this policy (e.g. "name", "description"). """ rules: List[FailureRule] = field(default_factory=list) attrs: Dict[str, Any] = field(default_factory=dict) def apply_failures( - self, nodes: Dict[str, Dict[str, Any]], links: Dict[str, Dict[str, Any]] + self, + nodes: Dict[str, Dict[str, Any]], + links: Dict[str, Dict[str, Any]], ) -> List[str]: """ - Identify which entities (nodes or links) fail according to the - defined rules. - - :param nodes: - A mapping of node_name -> node.attrs, where node.attrs has at least - a "type" = "node". - :param links: - A mapping of link_id -> link.attrs, where link.attrs has at least - a "type" = "link". - :returns: - A list of failed entity IDs. For nodes, that ID is typically the - node's name. For links, it's the link's ID. + Identify which entities (nodes or links) fail, given the defined rules. + Returns a combined list (union) of all entity IDs that fail. + + Args: + nodes: A mapping of node_name -> node.attrs (must have "type"="node"). + links: A mapping of link_id -> link.attrs (must have "type"="link"). + + Returns: + A list of failed entity IDs (node names or link IDs). """ # Merge nodes and links into a single map of entity_id -> entity_attrs - # e.g. { "SEA": { "type": "node", ...}, "SEA-DEN-xxx": { "type": "link", ...} } + # Example: { "SEA": {...}, "SEA-DEN-xxx": {...} } all_entities = {**nodes, **links} failed_entities = set() - # Evaluate each rule to find matched entities and union them + # Apply each rule, union all selected entities for rule in self.rules: matched = self._match_entities(all_entities, rule.conditions, rule.logic) selected = self._select_entities(matched, all_entities, rule) @@ -122,17 +138,16 @@ def _match_entities( logic: str, ) -> List[str]: """ - Find which entities (by ID) satisfy the given list of conditions + Find which entity IDs satisfy the given conditions combined by 'and'/'or' logic (or 'any' to skip checks). - :param all_entities: - Mapping of entity_id -> attribute dict. - :param conditions: - List of :class:`FailureCondition` to apply. - :param logic: - "and", "or", or "any". - :returns: - A list of entity IDs that match. + Args: + all_entities: Mapping of entity_id -> attribute dict. + conditions: List of FailureCondition to apply. + logic: "and", "or", or "any". + + Returns: + A list of entity IDs that match according to the logic. """ matched = [] for entity_id, attr_dict in all_entities.items(): @@ -142,30 +157,30 @@ def _match_entities( @staticmethod def _evaluate_conditions( - entity_attrs: Dict[str, Any], conditions: List[FailureCondition], logic: str + entity_attrs: Dict[str, Any], + conditions: List[FailureCondition], + logic: str, ) -> bool: """ - Check if the given entity (via entity_attrs) meets all/any of the conditions. - - :param entity_attrs: - The dictionary of attributes for a single entity (node or link). - :param conditions: - A list of conditions to evaluate. - :param logic: - "and" -> all must be true - "or" -> at least one true - "any" -> skip condition checks (always true) - :returns: - True if conditions pass for the specified logic, else False. + Check if the given entity meets all or any of the conditions, or if logic='any'. + + Args: + entity_attrs: Attributes dict for one entity (node or link). + conditions: List of FailureCondition. + logic: "and", "or", or "any". + + Returns: + True if conditions pass, else False. """ if logic == "any": - return True # means "select everything" + # 'any' means skip condition checks and always match + return True if not conditions: - return False # no conditions => no match, unless logic='any' + # If we have zero conditions, we treat this as no match unless logic='any' + return False - results = [] - for cond in conditions: - results.append(_evaluate_condition(entity_attrs, cond)) + # Evaluate each condition + results = [_evaluate_condition(entity_attrs, c) for c in conditions] if logic == "and": return all(results) @@ -181,22 +196,23 @@ def _select_entities( rule: FailureRule, ) -> List[str]: """ - Select which entity IDs will fail from the matched set, based on rule_type. - - :param entity_ids: - IDs that matched the rule's conditions. - :param all_entities: - The full entity dictionary (not strictly needed for some rule_types). - :param rule: - The FailureRule specifying how to pick the final subset. - :returns: - The final list of entity IDs that fail from this rule. + From the matched set, pick which entities fail according to rule_type. + + Args: + entity_ids: IDs that matched the rule's conditions. + all_entities: Full entity dictionary (for potential future use). + rule: The FailureRule specifying random/choice/all selection. + + Returns: + The final list of entity IDs that fail under this rule. """ if rule.rule_type == "random": - return [e for e in entity_ids if random() < rule.probability] + # Each entity is chosen with probability=rule.probability + return [ent_id for ent_id in entity_ids if random() < rule.probability] elif rule.rule_type == "choice": + # Sample exactly 'count' from the matched set (or fewer if matched < count) count = min(rule.count, len(entity_ids)) - # Use sorted(...) to ensure consistent picks when testing + # Use sorted(...) for deterministic results return sample(sorted(entity_ids), k=count) elif rule.rule_type == "all": return entity_ids @@ -206,19 +222,21 @@ def _select_entities( def _evaluate_condition(entity: Dict[str, Any], cond: FailureCondition) -> bool: """ - Evaluate one condition (attr, operator, value) against an entity's attrs. + Evaluate one FailureCondition (attr, operator, value) against entity attributes. + + Args: + entity: The entity's attributes (e.g., node.attrs or link.attrs). + cond: FailureCondition specifying (attr, operator, value). - :param entity: - The entity's attribute dictionary (node.attrs or link.attrs). - :param cond: - A single :class:`FailureCondition` specifying 'attr', 'operator', 'value'. - :returns: + Returns: True if the condition passes, else False. - :raises ValueError: - If the condition's operator is not recognized. + + Raises: + ValueError: If the operator is not recognized. """ derived_value = entity.get(cond.attr, None) op = cond.operator + if op == "==": return derived_value == cond.value elif op == "!=": diff --git a/ngraph/traffic_manager.py b/ngraph/traffic_manager.py index 3a7f405..7420b23 100644 --- a/ngraph/traffic_manager.py +++ b/ngraph/traffic_manager.py @@ -1,7 +1,7 @@ from collections import defaultdict from dataclasses import dataclass, field import statistics -from typing import Dict, List, Optional, Tuple, Union +from typing import Dict, List, Optional, Tuple, Union, NamedTuple from ngraph.lib.algorithms import base from ngraph.lib.algorithms.flow_init import init_flow_graph @@ -12,6 +12,27 @@ from ngraph.traffic_demand import TrafficDemand +class TrafficResult(NamedTuple): + """ + A container for traffic demand result data. + + Attributes: + priority (int): Demand priority class (lower=more critical). + total_volume (float): Total traffic volume for this entry. + placed_volume (float): The volume actually placed in the flow graph. + unplaced_volume (float): The volume not placed (total_volume - placed_volume). + src (str): Source node/path. + dst (str): Destination node/path. + """ + + priority: int + total_volume: float + placed_volume: float + unplaced_volume: float + src: str + dst: str + + @dataclass class TrafficManager: """ @@ -262,6 +283,61 @@ def summarize_link_usage(self) -> Dict[str, float]: return usage + def get_traffic_results(self, detailed: bool = False) -> List[TrafficResult]: + """ + Returns traffic demand summaries. + + If detailed=False, each top-level TrafficDemand is returned as a single entry. + If detailed=True, each expanded Demand is returned separately. + + Args: + detailed (bool): Whether to return per-expanded-demand data + instead of top-level aggregated data. + + Returns: + List[TrafficResult]: A list of traffic result tuples, each containing: + (priority, total_volume, placed_volume, unplaced_volume, src, dst). + """ + results: List[TrafficResult] = [] + + if not detailed: + # Summaries for top-level TrafficDemands + for td in self.traffic_demands: + total_volume = td.demand + placed_volume = td.demand_placed + unplaced_volume = total_volume - placed_volume + + # For aggregated results, we return the original src/dst "paths." + results.append( + TrafficResult( + priority=td.priority, + total_volume=total_volume, + placed_volume=placed_volume, + unplaced_volume=unplaced_volume, + src=td.source_path, + dst=td.sink_path, + ) + ) + else: + # Summaries for each expanded Demand + for dmd in self.demands: + total_volume = dmd.volume + placed_volume = dmd.placed_demand + unplaced_volume = total_volume - placed_volume + + results.append( + TrafficResult( + priority=dmd.demand_class, + total_volume=total_volume, + placed_volume=placed_volume, + unplaced_volume=unplaced_volume, + src=dmd.src_node, + dst=dmd.dst_node, + ) + ) + + return results + def _reoptimize_priority_demands(self, demands_in_prio: List[Demand]) -> None: """ Re-run flow-policy placement for each Demand in the same priority class. diff --git a/notebooks/scenario.ipynb b/notebooks/scenario.ipynb index 00fbce2..6c329b8 100644 --- a/notebooks/scenario.ipynb +++ b/notebooks/scenario.ipynb @@ -10,12 +10,14 @@ "from ngraph.traffic_demand import TrafficDemand\n", "from ngraph.traffic_manager import TrafficManager\n", "from ngraph.lib.flow_policy import FlowPolicyConfig, FlowPolicy, FlowPlacement\n", - "from ngraph.lib.algorithms.base import PathAlg, EdgeSelect" + "from ngraph.lib.algorithms.base import PathAlg, EdgeSelect\n", + "from ngraph.failure_manager import FailureManager\n", + "from ngraph.failure_policy import FailurePolicy, FailureRule, FailureCondition" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -78,7 +80,25 @@ " target: my_clos2/spine\n", " pattern: one_to_one\n", " link_params:\n", - " capacity: 2\n", + " capacity: 1\n", + " cost: 1\n", + " - source: my_clos1/spine\n", + " target: my_clos2/spine\n", + " pattern: one_to_one\n", + " link_params:\n", + " capacity: 1\n", + " cost: 1\n", + " - source: my_clos1/spine\n", + " target: my_clos2/spine\n", + " pattern: one_to_one\n", + " link_params:\n", + " capacity: 1\n", + " cost: 1\n", + " - source: my_clos1/spine\n", + " target: my_clos2/spine\n", + " pattern: one_to_one\n", + " link_params:\n", + " capacity: 1\n", " cost: 1\n", "\"\"\"\n", "scenario = Scenario.from_yaml(scenario_yaml)\n", @@ -87,16 +107,16 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{('b1|b2', 'b1|b2'): 128.0}" + "{('b1|b2', 'b1|b2'): 256.0}" ] }, - "execution_count": 3, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -112,16 +132,16 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "0.0" + "237.94000000003672" ] }, - "execution_count": 4, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -130,7 +150,7 @@ "d = TrafficDemand(\n", " source_path=r\"my_clos1.*(b[0-9]*)/t1\",\n", " sink_path=r\"my_clos2.*(b[0-9])/t1\",\n", - " demand=10,\n", + " demand=256,\n", " mode=\"full_mesh\",\n", " flow_policy_config=FlowPolicyConfig.SHORTEST_PATHS_ECMP,\n", ")\n", @@ -146,346 +166,130 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 25, "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "TrafficDemand(source_path='my_clos1.*(b[0-9]*)/t1', sink_path='my_clos2.*(b[0-9])/t1', priority=0, demand=10, demand_placed=0.0, flow_policy_config=, flow_policy=None, mode='full_mesh', attrs={}, id='my_clos1.*(b[0-9]*)/t1|my_clos2.*(b[0-9])/t1|S6weVhAgQMCerTqMbTnMVw')" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "Overall Statistics:\n", + " mean: 203.43\n", + " stdev: 21.25\n", + " min: 179.14\n", + " max: 251.71\n" + ] } ], "source": [ - "d" + "my_rules = [\n", + " FailureRule(\n", + " conditions=[FailureCondition(attr=\"type\", operator=\"==\", value=\"link\")],\n", + " logic=\"and\",\n", + " rule_type=\"choice\",\n", + " count=2,\n", + " ),\n", + "]\n", + "fpolicy = FailurePolicy(rules=my_rules)\n", + "\n", + "# Run Monte Carlo\n", + "fmgr = FailureManager(network, demands, failure_policy=fpolicy)\n", + "results = fmgr.run_monte_carlo_failures(iterations=30, parallelism=10)\n", + "overall = results[\"overall_stats\"]\n", + "print(\"Overall Statistics:\")\n", + "for k, v in overall.items():\n", + " print(f\" {k}: {v:.2f}\")" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 26, "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "[Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-2', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-3', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-4', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-5', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-6', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-7', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b1/t1/t1-8', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-1', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-2', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-3', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-4', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-5', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-6', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-7', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b1/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b1/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b1/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b1/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b1/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b1/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b1/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b1/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b2/t1/t1-1', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b2/t1/t1-2', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b2/t1/t1-3', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b2/t1/t1-4', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b2/t1/t1-5', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b2/t1/t1-6', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b2/t1/t1-7', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0),\n", - " Demand(src_node='my_clos1/b2/t1/t1-8', dst_node='my_clos2/b2/t1/t1-8', volume=0.0390625, demand_class=0, flow_policy=, placed_demand=0.0)]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tm.demands" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/xh/83kdwyfd0fv66b04mchbfzcc0000gn/T/ipykernel_93610/4192461833.py:60: UserWarning: No artists with labels found to put in legend. Note that artists whose label start with an underscore are ignored when legend() is called with no argument.\n", + " plt.legend(title=\"Priority\")\n" + ] + }, { "data": { + "image/png": "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iIgwOE3Tpk2xevVqHD9+HE2aNMHNmzexa9cu9O7dO8vlpKamIjU1Vfc6ISEBAKDRaKDRaAppbXInc3nFvVy5er0OGo0GGoUwUm+Mj9uHFOshxXpIsR5SrMdLcqxFbvtitFD26NEjZGRkwMnJSdLu5OSEK1euGJymR48eePToEd577z0IIZCeno4hQ4Zke/hyxowZCAkJ0Wvfu3cvLCwsCrYS+RQWFmaU5crdnj17oVYauxfGx+1DivWQYj2kWA8p1uMlOdUiOTk5V+MZLZTlx8GDBzF9+nQsXLgQXl5euH79OkaMGIGpU6fi66+/NjhNcHAwgoKCdK8TEhLg5uYGPz8/WFtbF1fXAbxIymFhYWjdujVUKlWxLluONBoNdux++aHx9/eDhekbtUkWKm4fUqyHFOshxXpIsR4vybEWmUfpcmK0X0AHBwcolUrExsZK2mNjY+Hs7Gxwmq+//hq9e/fGgAEDAAB169ZFUlISBg0ahP/+978wMdE/RU6tVkOtVuu1q1Qqo71Zxly2nL2oS8kNZZm4fUixHlKshxTrIcV6vCSnWuS2H0Y70d/U1BSenp4IDw/XtWm1WoSHh8Pb29vgNMnJyXrBS6l8cbxLiJJ7LhIRERG9+Yy6WyIoKAh9+vRBo0aN0KRJE8ydOxdJSUno168fACAwMBDlypXDjBkzAAABAQEIDQ1Fw4YNdYcvv/76awQEBOjCGREREdGbyKihrGvXrnj48CEmTpyImJgYNGjQALt379ad/H/nzh3JnrEJEyZAoVBgwoQJuHfvHhwdHREQEIBp06YZaxWIiIiICoXRT+AZPnw4hg8fbnDYwYMHJa9LlSqFSZMmYdKkScXQMyIiIqLiY/THLBERERERQxkRERGRLDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDDCUEREREckAQxkRERGRDBg9lC1YsAAeHh4wMzODl5cXjh8/nu34T58+xbBhw+Di4gK1Wo1q1aph165dxdRbIiIioqJRypgL37BhA4KCgrB48WJ4eXlh7ty58Pf3x9WrV1G2bFm98dPS0tC6dWuULVsWv//+O8qVK4fbt2/D1ta2+DtPREREVIiMGspCQ0MxcOBA9OvXDwCwePFi7Ny5E8uWLcO4ceP0xl+2bBni4uJw9OhRqFQqAICHh0dxdpmKUHJaRq7GM1cpoVAoirg3RERExctooSwtLQ2nTp1CcHCwrs3ExAS+vr6IiIgwOM327dvh7e2NYcOGYdu2bXB0dESPHj3w1VdfQalUGpwmNTUVqamputcJCQkAAI1GA41GU4hrlLPM5RX3cuXq9To0+mZfrqbzrGCLdQMav3XBjNuHFOshxXpIsR5SrMdLcqxFbvtitFD26NEjZGRkwMnJSdLu5OSEK1euGJzm5s2b2L9/P3r27Ildu3bh+vXrGDp0KDQaDSZNmmRwmhkzZiAkJESvfe/evbCwsCj4iuRDWFiYUZYrR6YmQMXSAlGJuQ9Yp+48xdYdf0JtOIe/8bh9SLEeUqyHFOshxXq8JKdaJCcn52o8ox6+zCutVouyZctiyZIlUCqV8PT0xL179/Ddd99lGcqCg4MRFBSke52QkAA3Nzf4+fnB2tq6uLoO4EVSDgsLQ+vWrXWHX0uyzHrsGPk+0nNxzUlKWgbenXUIAODv7wcL0zdq880Rtw8p1kOK9ZBiPaRYj5fkWIvMo3Q5MdqvmoODA5RKJWJjYyXtsbGxcHZ2NjiNi4sLVCqV5FBlzZo1ERMTg7S0NJiamupNo1aroVar9dpVKpXR3ixjLluOTE1NYZmLeqhU6a/8WwWV6u0KZZm4fUixHlKshxTrIcV6vCSnWuS2H0a7JYapqSk8PT0RHh6ua9NqtQgPD4e3t7fBaZo1a4br169Dq9Xq2v7991+4uLgYDGREREREbwqj3qcsKCgIP//8M1auXInLly/j888/R1JSku5qzMDAQMmFAJ9//jni4uIwYsQI/Pvvv9i5cyemT5+OYcOGGWsViIiIiAqFUY//dO3aFQ8fPsTEiRMRExODBg0aYPfu3bqT/+/cuQMTk5e50c3NDXv27MGXX36JevXqoVy5chgxYgS++uorY60CERERUaEw+kk5w4cPx/Dhww0OO3jwoF6bt7c3/vnnnyLuFREREVHxMvpjloiIiIiIoYyIiIhIFhjKiIiIiGSAoYyIiIhIBhjKiIiIiGQg31dfajQaxMTEIDk5GY6OjrC3ty/MfhERERGVKHnaU5aYmIhFixbBx8cH1tbW8PDwQM2aNeHo6Ah3d3cMHDgQJ06cKKq+EhEREb21ch3KQkND4eHhgeXLl8PX1xdbt25FZGQk/v33X0RERGDSpElIT0+Hn58f2rRpg2vXrhVlv4mIiIjeKrk+fHnixAkcPnwYtWvXNji8SZMm+Oyzz7B48WIsX74cf/31F6pWrVpoHSUiIiJ6m+U6lK1bty5X46nVagwZMiTfHSIiIiIqifJ19eXDhw+zHHb+/Pl8d4aIiIiopMpXKKtbty527typ1z579mw0adKkwJ0iIiIiKmnyFcqCgoLwySef4PPPP0dKSgru3buHDz74AN9++y3Wrl1b2H0kIiIieuvlK5SNHTsWERER+Ouvv1CvXj3Uq1cParUa586dw0cffVTYfSQiIiJ66+X7jv5VqlRBnTp1cOvWLSQkJKBr165wdnYuzL4RERERlRj5CmVHjhxBvXr1cO3aNZw7dw6LFi3CF198ga5du+LJkyeF3UciIiKit16+QlmrVq3QtWtX/PPPP6hZsyYGDBiAM2fO4M6dO6hbt25h95GIiIjorZevZ1/u3bsXPj4+krbKlSvjyJEjmDZtWqF0jIiIiKgkydeestcDmW5mJib4+uuvC9QhIiIiopIo3yf6ExEREVHhYSgjIiIikgGGMiIiIiIZYCgjIiIikgGGMiIiIiIZKFAo69SpE7744gvd6xs3bsDV1bXAnSIiIiIqafIdyuLj47Fr1y5s3LhR15aeno7Y2NhC6RgRERFRSZLvULZ37144OzsjOTkZJ06cKMw+EREREZU4+Q5lu3btQvv27dGqVSvs2rWrMPtEREREVOLkO5Tt2bMHHTp0QLt27RjKiIiIiAooX6Hs1KlTiI+PxwcffIC2bdvi9OnTePToUWH3jYiIiKjEyFco27VrF1q2bAkzMzO4ubmhRo0a2L17d2H3jYiIiKjEyHcoa9++ve51u3btsHPnzkLrFBEREVFJk+dQlpKSAqVSiQ4dOujaPv74Y8THx8Pc3BxNmjQp1A4SERERlQSl8jqBubk5/v77b0mbl5eX7mT/iIiIwukZERERUQnCxywRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyUCeQtnSpUuzHZ6YmIgBAwYUqENEREREJVGeQllQUBA6dOiAmJgYvWF79uxB7dq1ceLEiULrHBEREVFJkadQdvbsWSQlJaF27dpYt24dgBd7x/r374+AgAD06tULJ0+eLJKOEhEREb3N8nTzWA8PDxw4cABz587FwIEDsWbNGpw/fx5WVlY4cuQIGjduXFT9JCIiInqr5fmO/gAwePBgHD58GFu3boWlpSV27NiBunXrFnbfiIiIiEqMPF99eeTIEdSvXx9XrlzB7t270bZtW3h7e2PevHlF0T8iIiKiEiFPoWzUqFFo1aoVAgICcPr0afj5+eG3337D0qVL8c0336Bly5aIiooqqr4SERERvbXyFMq2bduGffv2Yc6cOTAzM9O1d+3aFRcuXICNjQ3q1atX6J0kIiIietvl6Zyyc+fOwcLCwuAwJycnbNu2DatWrSqUjhERERGVJHnaU5ZVIHtV7969890ZIiIiopIq16Fs5syZSE5OztW4x44dw86dO/PdKSIiIqKSJteh7NKlS3B3d8fQoUPx559/4uHDh7ph6enpOHfuHBYuXIimTZuia9euKF26dJF0mIiIiOhtlOtzyn799VecPXsWP/74I3r06IGEhAQolUqo1WrdHrSGDRtiwIAB6Nu3r+RCACIiIiLKXp5O9K9fvz5+/vln/PTTTzh79izu3LmDlJQUODg4oEGDBnBwcCiqfhIRERG91fJ1R38TExM0bNgQDRs2LOz+EBEREZVIebr6MiMjA7NmzUKzZs3QuHFjjBs3DikpKUXVNyIiIqISI0+hbPr06Rg/fjysrKxQrlw5zJs3D8OGDSuqvhERERGVGHkKZb/++isWLlyIPXv2YOvWrfjjjz+wZs0aaLXaouofERERUYmQp1B2584dtGvXTvfa19cXCoUC9+/fL/SOEREREZUkeQpl6enpere6UKlU0Gg0hdopIiIiopImT1dfCiHQt29fqNVqXdvz588xZMgQWFpa6to2b95ceD0kIiIiKgHyFMr69Omj19arV69C6wwRERFRSZWnULZ8+fKi6gcRERFRiZanc8qIiIiIqGgwlBERERHJAEMZERERkQwwlBERERHJgCxC2YIFC+Dh4QEzMzN4eXnh+PHjuZpu/fr1UCgU6NSpU9F2kIiIiKiIGT2UbdiwAUFBQZg0aRJOnz6N+vXrw9/fHw8ePMh2ulu3bmH06NFo3rx5MfWUiIiIqOgYPZSFhoZi4MCB6NevH2rVqoXFixfDwsICy5Yty3KajIwM9OzZEyEhIahUqVIx9paIiIioaOTpPmWFLS0tDadOnUJwcLCuzcTEBL6+voiIiMhyuilTpqBs2bLo378//vrrr2yXkZqaitTUVN3rhIQEAIBGoyn2x0NlLo+PpXohr/XQaNIl02oUokj6ZSzcPqRYDynWQ4r1kGI9XpJjLXLbF6OGskePHiEjIwNOTk6SdicnJ1y5csXgNH///TeWLl2KyMjIXC1jxowZCAkJ0Wvfu3cvLCws8tznwhAWFmaU5cpVbuuRmgFkbrJ79uyFWll0fTImbh9SrIcU6yHFekixHi/JqRbJycm5Gs+ooSyvEhMT0bt3b/z8889wcHDI1TTBwcEICgrSvU5ISICbmxv8/PxgbW1dVF01SKPRICwsDK1bt4ZKpSrWZctRXuuRnJaOscf3AwD8/f1gYfpGbb454vYhxXpIsR5SrIcU6/GSHGuReZQuJ0b9VXNwcIBSqURsbKykPTY2Fs7Oznrj37hxA7du3UJAQICuTavVAgBKlSqFq1evonLlypJp1Gq15AHqmVQqldHeLGMuW45yWw+VULw2zdsVyjJx+5BiPaRYDynWQ4r1eElOtchtP4x6or+pqSk8PT0RHh6ua9NqtQgPD4e3t7fe+DVq1MD58+cRGRmp+/vwww/x/vvvIzIyEm5ubsXZfSIiIqJCY/RdDUFBQejTpw8aNWqEJk2aYO7cuUhKSkK/fv0AAIGBgShXrhxmzJgBMzMz1KlTRzK9ra0tAOi1ExEREb1JjB7KunbtiocPH2LixImIiYlBgwYNsHv3bt3J/3fu3IGJidHv3EFERERUpIweygBg+PDhGD58uMFhBw8ezHbaFStWFH6HiIiIiIoZd0ERERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyUApY3eAKD+S0zKM3YVCp9GkIzUDSE5Lh0oojN0dg8xVSigU8uwbEdGbjqGM3kiNvtln7C4UkVIYe3y/sTuRpUbudtg4xJvBjIioCPDwJb0xzFVKNHK3M3Y3SrSTt58gRfP27aUkIpID7imjN4ZCocDGId5vbSjQaDTYs2cv/P39oFKpjN0dieS0jLd47yQRkTwwlNEbRaFQwML07dxsNQoBtRKwMC0FlertXEciIsoaD18SERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEMMJQRERERyQBDGREREZEM8A6VRJQnxfUw+DfhAe3FqbjrwYfPExU/hjIiypPifdySvB/QXvyKrx58+DxR8ePhSyLKER8GX/Lw4fNExY97yogoR8Z4GLycH9BuDMVVDz58nsh4GMqIKFeK+2HwfEC7FOtB9Pbj4UsiIiIiGWAoIyIiIpIBhjIiIiIiGWAoIyIiIpIBhjIiIiIiGWAoIyIiIpIBhjIiIiIiGWAoIyIiIpIBhjIiIiIiGWAoIyIiIpIBhjIiIiIiGWAoIyIiIpIBhjIiIiIiGWAoIyIiIpIBhjIiIiIiGWAoIyIiIpIBhjIiIiIiGWAoIyIiIpIBhjIiIiIiGZBFKFuwYAE8PDxgZmYGLy8vHD9+PMtxf/75ZzRv3hx2dnaws7ODr69vtuMTERERvQmMHso2bNiAoKAgTJo0CadPn0b9+vXh7++PBw8eGBz/4MGD6N69Ow4cOICIiAi4ubnBz88P9+7dK+aeExERERWeUsbuQGhoKAYOHIh+/foBABYvXoyd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", "text/plain": [ - "{'path_alg': ,\n", - " 'flow_placement': ,\n", - " 'edge_select': ,\n", - " 'multipath': False,\n", - " 'min_flow_count': 16,\n", - " 'max_flow_count': 16,\n", - " 'max_path_cost': None,\n", - " 'max_path_cost_factor': None,\n", - " 'static_paths': None,\n", - " 'edge_select_func': None,\n", - " 'edge_select_value': None,\n", - " 'reoptimize_flows_on_each_placement': True,\n", - " 'flows': {FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=0): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=1): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=2): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=3): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=4): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=5): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=6): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=7): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=8): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=9): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=10): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=11): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=12): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=13): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=14): ,\n", - " FlowIndex(src_node='my_clos1/b1/t1/t1-1', dst_node='my_clos2/b1/t1/t1-1', flow_class=0, flow_id=15): },\n", - " 'best_path_cost': 500.0,\n", - " '_next_flow_id': 16}" + "
" ] }, - "execution_count": 7, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ - "vars(dmd.flow_policy)" + "import pandas as pd\n", + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "from collections import defaultdict\n", + "\n", + "\n", + "def plot_priority_cdf(results, complementary: bool = True):\n", + " \"\"\"\n", + " Plots an empirical (complementary) CDF of placed volume for each priority.\n", + "\n", + " Args:\n", + " results: The dictionary returned by run_monte_carlo_failures, containing:\n", + " {\n", + " \"overall_stats\": {...},\n", + " \"by_src_dst\": {\n", + " (src, dst, priority): [\n", + " {\"iteration\": int, \"total_volume\": float, \"placed_volume\": float, ...},\n", + " ...\n", + " ],\n", + " ...\n", + " }\n", + " }\n", + " complementary: If True, plots a complementary CDF (P(X >= x)).\n", + " If False, plots a standard CDF (P(X <= x)).\n", + " \"\"\"\n", + " by_src_dst = results[\"by_src_dst\"] # {(src, dst, priority): [...]}\n", + "\n", + " # 1) Aggregate total placed volume for each iteration & priority\n", + " # (similar logic as before, but we'll directly store iteration-level sums).\n", + " volume_per_iter_priority = defaultdict(float)\n", + " for (src, dst, priority), data_list in by_src_dst.items():\n", + " for entry in data_list:\n", + " it = entry[\"iteration\"]\n", + " volume_per_iter_priority[(it, priority)] += entry[\"placed_volume\"]\n", + "\n", + " # 2) Convert to a tidy DataFrame with columns: [iteration, priority, placed_volume]\n", + " rows = []\n", + " for (it, prio), vol_sum in volume_per_iter_priority.items():\n", + " rows.append({\"iteration\": it, \"priority\": prio, \"placed_volume\": vol_sum})\n", + "\n", + " plot_df = pd.DataFrame(rows)\n", + "\n", + " # 3) Use seaborn's ECDF plot (which can do either standard or complementary CDF)\n", + " plt.figure(figsize=(7, 5))\n", + " sns.ecdfplot(\n", + " data=plot_df,\n", + " x=\"placed_volume\",\n", + " hue=\"priority\",\n", + " complementary=complementary, # True -> CCDF, False -> normal CDF\n", + " )\n", + " if complementary:\n", + " plt.ylabel(\"P(X ≥ x)\")\n", + " plt.title(\"Per-Priority Complementary CDF of Placed Volume\")\n", + " else:\n", + " plt.ylabel(\"P(X ≤ x)\")\n", + " plt.title(\"Per-Priority CDF of Placed Volume\")\n", + "\n", + " plt.xlabel(\"Total Placed Volume (per iteration)\")\n", + " plt.grid(True)\n", + " plt.legend(title=\"Priority\")\n", + " plt.show()\n", + "\n", + "\n", + "plot_priority_cdf(results, complementary=True)" ] }, { diff --git a/tests/test_failure_manager.py b/tests/test_failure_manager.py new file mode 100644 index 0000000..2161e99 --- /dev/null +++ b/tests/test_failure_manager.py @@ -0,0 +1,196 @@ +"""Tests for the FailureManager class.""" + +import pytest +from unittest.mock import MagicMock +from typing import List + +from ngraph.network import Network +from ngraph.traffic_demand import TrafficDemand +from ngraph.traffic_manager import TrafficManager, TrafficResult +from ngraph.failure_policy import FailurePolicy +from ngraph.failure_manager import FailureManager + + +@pytest.fixture +def mock_network() -> Network: + """Fixture returning a mock Network with a node1 and link1.""" + mock_net = MagicMock(spec=Network) + # Populate these so that 'node1' and 'link1' are found in membership tests. + mock_net.nodes = {"node1": MagicMock()} + mock_net.links = {"link1": MagicMock()} + return mock_net + + +@pytest.fixture +def mock_demands() -> List[TrafficDemand]: + """Fixture returning a list of mock TrafficDemands.""" + return [MagicMock(spec=TrafficDemand), MagicMock(spec=TrafficDemand)] + + +@pytest.fixture +def mock_failure_policy() -> FailurePolicy: + """Fixture returning a mock FailurePolicy.""" + policy = MagicMock(spec=FailurePolicy) + # By default, pretend both "node1" and "link1" fail. + policy.apply_failures.return_value = ["node1", "link1"] + return policy + + +@pytest.fixture +def mock_traffic_manager_results() -> List[TrafficResult]: + """Fixture returning mock traffic results.""" + result1 = MagicMock(spec=TrafficResult) + result1.src = "A" + result1.dst = "B" + result1.priority = 1 + result1.placed_volume = 50.0 + result1.total_volume = 100.0 + result1.unplaced_volume = 50.0 + + result2 = MagicMock(spec=TrafficResult) + result2.src = "C" + result2.dst = "D" + result2.priority = 2 + result2.placed_volume = 30.0 + result2.total_volume = 30.0 + result2.unplaced_volume = 0.0 + + return [result1, result2] + + +@pytest.fixture +def mock_traffic_manager_class(mock_traffic_manager_results): + """Mock TrafficManager class.""" + + class MockTrafficManager(MagicMock): + def build_graph(self): + pass + + def expand_demands(self): + pass + + def place_all_demands(self): + pass + + def get_traffic_results(self, detailed: bool = True): + return mock_traffic_manager_results + + return MockTrafficManager + + +@pytest.fixture +def failure_manager( + mock_network, + mock_demands, + mock_failure_policy, +): + """Factory fixture to create a FailureManager with default mocks.""" + return FailureManager( + network=mock_network, + traffic_demands=mock_demands, + failure_policy=mock_failure_policy, + default_flow_policy_config=None, + ) + + +def test_apply_failures_no_policy(mock_network, mock_demands): + """Test apply_failures does nothing if there is no failure_policy.""" + fmgr = FailureManager( + network=mock_network, traffic_demands=mock_demands, failure_policy=None + ) + fmgr.apply_failures() + + mock_network.disable_node.assert_not_called() + mock_network.disable_link.assert_not_called() + + +def test_apply_failures_with_policy(failure_manager, mock_network): + """ + Test apply_failures applies the policy's returned list of failed IDs + to disable_node/disable_link on the network. + """ + failure_manager.apply_failures() + + # We expect that one node and one link are disabled + mock_network.disable_node.assert_called_once_with("node1") + mock_network.disable_link.assert_called_once_with("link1") + + +def test_run_single_failure_scenario( + failure_manager, mock_network, mock_traffic_manager_class, monkeypatch +): + """ + Test run_single_failure_scenario applies failures, builds TrafficManager, + and returns traffic results. + """ + # Patch TrafficManager constructor in the 'ngraph.failure_manager' namespace + monkeypatch.setattr( + "ngraph.failure_manager.TrafficManager", mock_traffic_manager_class + ) + + results = failure_manager.run_single_failure_scenario() + assert len(results) == 2 # We expect two mock results + + # Verify network was re-enabled before applying failures + mock_network.enable_all.assert_called_once() + # Verify that apply_failures was indeed called + mock_network.disable_node.assert_called_once_with("node1") + mock_network.disable_link.assert_called_once_with("link1") + + +def test_run_monte_carlo_failures_zero_iterations(failure_manager): + """ + Test run_monte_carlo_failures(0) returns zeroed stats. + """ + stats = failure_manager.run_monte_carlo_failures(iterations=0, parallelism=1) + + # Overall stats should be zeroed out + assert stats["overall_stats"]["mean"] == 0.0 + assert stats["overall_stats"]["stdev"] == 0.0 + assert stats["overall_stats"]["min"] == 0.0 + assert stats["overall_stats"]["max"] == 0.0 + assert stats["by_src_dst"] == {} + + +def test_run_monte_carlo_failures_single_thread( + failure_manager, mock_network, mock_traffic_manager_class, monkeypatch +): + """Test run_monte_carlo_failures with single-thread (parallelism=1).""" + monkeypatch.setattr( + "ngraph.failure_manager.TrafficManager", mock_traffic_manager_class + ) + stats = failure_manager.run_monte_carlo_failures(iterations=2, parallelism=1) + + # Validate structure of returned dictionary + assert "overall_stats" in stats + assert "by_src_dst" in stats + assert len(stats["by_src_dst"]) > 0 + + overall_stats = stats["overall_stats"] + assert overall_stats["min"] <= overall_stats["mean"] <= overall_stats["max"] + + # We expect at least one entry for each iteration for (A,B,1) and (C,D,2) + key1 = ("A", "B", 1) + key2 = ("C", "D", 2) + assert key1 in stats["by_src_dst"] + assert key2 in stats["by_src_dst"] + assert len(stats["by_src_dst"][key1]) == 2 + assert len(stats["by_src_dst"][key2]) == 2 + + +def test_run_monte_carlo_failures_multi_thread( + failure_manager, mock_network, mock_traffic_manager_class, monkeypatch +): + """Test run_monte_carlo_failures with parallelism > 1.""" + monkeypatch.setattr( + "ngraph.failure_manager.TrafficManager", mock_traffic_manager_class + ) + stats = failure_manager.run_monte_carlo_failures(iterations=2, parallelism=2) + + # Verify the structure is still as expected + assert "overall_stats" in stats + assert "by_src_dst" in stats + + overall_stats = stats["overall_stats"] + assert overall_stats["mean"] > 0 + assert overall_stats["max"] >= overall_stats["min"]