Node-scanwidth#
Public function#
- scanwidth.node_scanwidth(dag: DAG, algorithm: str = 'xp', reduce: bool = True, **kwargs: object) Tuple[int, Extension]#
Compute node scanwidth of a DAG using the selected algorithm.
- Parameters:
dag (DAG) – Input directed acyclic graph.
algorithm (str, optional) –
Solver name. Supported values are:
"xp": exact XP algorithm with increasingk."brute_force": exact brute-force search over all extensions."ilp": exact MILP solver with backend selection (backend="scipy"orbackend="gurobi")."greedy": greedy heuristic."random": random extension heuristic."simulated_annealing": simulated-annealing heuristic.
reduce (bool, optional) – If True, apply reduction rules before solving. Default is True.
**kwargs (object) – Algorithm-specific keyword arguments plus optional
reducer_config=ReducerConfig(...). SetReducerConfig(parallel_sblocks=True)to solve independent s-blocks concurrently.
- Returns:
Node-scanwidth value and the corresponding extension.
- Return type:
Tuple[int, Extension]
Examples
>>> import networkx as nx >>> from scanwidth import DAG, node_scanwidth >>> from scanwidth.node_scanwidth.reduction.config import ReducerConfig >>> graph = nx.DiGraph([(1, 3), (2, 3)]) >>> value, extension = node_scanwidth( ... DAG(graph), ... algorithm="brute_force", ... reducer_config=ReducerConfig(parallel_sblocks=True, sblock_max_workers=2), ... ) >>> value == extension.node_scanwidth() True
Module details#
Public API entry point for node-scanwidth algorithms.
- scanwidth.node_scanwidth.api.node_scanwidth(dag: DAG, algorithm: str = 'xp', reduce: bool = True, **kwargs: object) Tuple[int, Extension]#
Compute node scanwidth of a DAG using the selected algorithm.
- Parameters:
dag (DAG) – Input directed acyclic graph.
algorithm (str, optional) –
Solver name. Supported values are:
"xp": exact XP algorithm with increasingk."brute_force": exact brute-force search over all extensions."ilp": exact MILP solver with backend selection (backend="scipy"orbackend="gurobi")."greedy": greedy heuristic."random": random extension heuristic."simulated_annealing": simulated-annealing heuristic.
reduce (bool, optional) – If True, apply reduction rules before solving. Default is True.
**kwargs (object) – Algorithm-specific keyword arguments plus optional
reducer_config=ReducerConfig(...). SetReducerConfig(parallel_sblocks=True)to solve independent s-blocks concurrently.
- Returns:
Node-scanwidth value and the corresponding extension.
- Return type:
Tuple[int, Extension]
Examples
>>> import networkx as nx >>> from scanwidth import DAG, node_scanwidth >>> from scanwidth.node_scanwidth.reduction.config import ReducerConfig >>> graph = nx.DiGraph([(1, 3), (2, 3)]) >>> value, extension = node_scanwidth( ... DAG(graph), ... algorithm="brute_force", ... reducer_config=ReducerConfig(parallel_sblocks=True, sblock_max_workers=2), ... ) >>> value == extension.node_scanwidth() True
Solver classes#
Node-scanwidth solver hierarchy.
- class scanwidth.node_scanwidth.solver.BruteForceSolver#
Bases:
SolverExhaustive search over all topological orders for node scanwidth.
- class scanwidth.node_scanwidth.solver.GreedySolver#
Bases:
SolverGreedy node-scanwidth solver.
- class scanwidth.node_scanwidth.solver.ILPSolver(backend: Literal['scipy', 'gurobi'] = 'scipy', time_limit: float | None = None, mip_rel_gap: float = 0.0, verbose: bool = False)#
Bases:
SolverExact node-scanwidth solver based on an ILP formulation.
- Parameters:
backend (Literal["scipy", "gurobi"], optional) – MILP backend used to solve the ILP model.
time_limit (Optional[float], optional) – Time limit in seconds for the MILP solve.
mip_rel_gap (float, optional) – Relative MIP gap tolerance for the selected backend.
verbose (bool, optional) – If True, enable backend output.
- backend: Literal['scipy', 'gurobi'] = 'scipy'#
- mip_rel_gap: float = 0.0#
- time_limit: float | None = None#
- verbose: bool = False#
- class scanwidth.node_scanwidth.solver.RandomSolver(seed: int = 42)#
Bases:
SolverRandom-extension node-scanwidth solver.
- seed: int = 42#
- class scanwidth.node_scanwidth.solver.SimulatedAnnealingSolver(max_iter: int = 100, p_in: float = 0.9, p_stop: float = 0.01, init_ext: str | Extension = 'greedy', verbose: bool = False, seed: int = 42)#
Bases:
SolverSimulated-annealing node-scanwidth solver.
- max_iter: int = 100#
- p_in: float = 0.9#
- p_stop: float = 0.01#
- seed: int = 42#
- verbose: bool = False#
Reduction configuration and reducer#
Configuration for node-scanwidth reduction pipeline.
- class scanwidth.node_scanwidth.reduction.config.ReducerConfig(use_sblocks: bool = True, use_single_edge_shortcut: bool = True, use_single_root_cycle_rule: bool = True, use_tree_shortcut: bool = True, use_chain_suppression: bool = True, use_reticulation_path_shortcut: bool = True, parallel_sblocks: bool = False, sblock_max_workers: int | None = None)#
Bases:
objectToggle reduction rules for
scanwidth.node_scanwidth.reduction.Reducer.- Parameters:
use_sblocks (bool, optional) – If True, decompose into s-block subproblems.
use_single_edge_shortcut (bool, optional) – If True, solve two-vertex single-edge blocks directly.
use_single_root_cycle_rule (bool, optional) – If True, solve single-root cycle-like blocks directly with node scanwidth 2 (same structure as edge reducer).
use_tree_shortcut (bool, optional) – If True, solve directed rooted trees directly.
use_chain_suppression (bool, optional) – If True, apply chain-parent suppression on blocks before solving.
use_reticulation_path_shortcut (bool, optional) – If True, apply the reticulation-path closed-form shortcut on eligible non-root s-blocks after chain suppression.
parallel_sblocks (bool, optional) – If True, solve independent s-block subproblems concurrently.
sblock_max_workers (Optional[int], optional) – Maximum number of workers used for s-block parallelization.
Nonedelegates worker selection to the executor default.
- parallel_sblocks: bool = False#
- sblock_max_workers: int | None = None#
- use_chain_suppression: bool = True#
- use_reticulation_path_shortcut: bool = True#
- use_sblocks: bool = True#
- use_single_edge_shortcut: bool = True#
- use_single_root_cycle_rule: bool = True#
- use_tree_shortcut: bool = True#
Reducer abstraction for node-scanwidth algorithms.
- class scanwidth.node_scanwidth.reduction.reducer.Reducer(config: ReducerConfig = ReducerConfig(use_sblocks=True, use_single_edge_shortcut=True, use_single_root_cycle_rule=True, use_tree_shortcut=True, use_chain_suppression=True, use_reticulation_path_shortcut=True, parallel_sblocks=False, sblock_max_workers=None))#
Bases:
objectApply node-scanwidth reductions and delegate each block to a solver.
- config: ReducerConfig = ReducerConfig(use_sblocks=True, use_single_edge_shortcut=True, use_single_root_cycle_rule=True, use_tree_shortcut=True, use_chain_suppression=True, use_reticulation_path_shortcut=True, parallel_sblocks=False, sblock_max_workers=None)#