spopt.locate.FRLM

class spopt.locate.FRLM(vehicle_range: float | int = 200000, p_facilities: int = 5, capacity: float | None = None, threshold: float = 0.0, weight: float = 0.99, objective: str = 'flow', include_destination: bool = False)[source]

Flow Refueling Location Model (FRLM)

Parameters:
vehicle_rangefloat | int, default=200000.0

Defines the maximum travel distance or range for vehicles.

  • If value is between 0 and 1: Treated as a percentage of the longest path. e.g. 0.5: 50% of the longest path in the network

  • If value > 1: Treated as an absolute distance in distance units (e.g., meters)

p_facilitiesint, default=5

Number of facility modules to be located in the network.

capacityfloat | None, default=None

Facility module capacity constraint.

  • If None: Uses an uncapacitated model

  • If provided: Sets a maximum capacity for each facility module

thresholdfloat, default=0.0

Minimum flow coverage percentage for a node to be considered covered, 0 disables threshold extension.

weightfloat, default=0.99

Controls the trade-off between node coverage and flow coverage for threshold extension objective. Range: [0.0, 1.0]

  • 1.0: Prioritises node coverage

  • 0.0: Prioritises flow coverage

Only used when threshold > 0.

objectivestr, default=”flow”

Optimisation objective.

  • “flow”: Maximize total flow coverage

  • “vmt”: Maximize vehicle miles traveled (VMT) coverage

include_destinationbool, default=False

Determines how node weights are calculated in threshold extension.

  • False: Only origin nodes contribute to weight calculation

  • True: Both origin and destination nodes contribute to weight calculation

__init__(vehicle_range: float | int = 200000, p_facilities: int = 5, capacity: float | None = None, threshold: float = 0.0, weight: float = 0.99, objective: str = 'flow', include_destination: bool = False)[source]

Methods

__init__([vehicle_range, p_facilities, ...])

add_flow(origin, destination, volume[, path])

Add flow with path calculation using scipy network.

add_flows(flows)

Add multiple flows to the FRLM instance.

add_network(network)

Add network to the FRLM instance.

calculate_covered_nodes()

calculate_node_weights([include_destination])

Calculate node weights based on flow volumes.

check_path_refueling_feasibility(path, ...)

Check if a path can be traversed with given facilities using scipy network.

compute_refueling_frequency(origin, destination)

extract_solver_statistics()

from_flow_dataframe(network, flows, **kwargs)

Create FRLM instance from network and flows.

generate_path_refueling_combinations([...])

Generate dictionary mapping OD pairs to valid facility combinations.

get_constraint_dual(constraint_name)

get_detailed_results()

get_flow_coverage()

Improved and fixed calculation of flow coverage.

get_node_coverage_percentage()

Get percentage of nodes covered.

get_reduced_costs()

get_shadow_price(constraint_name)

get_shadow_prices()

get_slack(constraint_name)

get_solver_details()

Retrieve detailed solver information.

get_variable_value(var_name)

get_variable_values()

get_vmt_coverage()

is_constraint_active(constraint_name)

solve([solver, seed, initialization_method, ...])

Solve the FRLM problem.

summary()

Generate a summary of the solution.

to_dataframes([include_iterations])

Export solution to pandas DataFrames.

Attributes

problem

Return the PuLP problem instance.

selected_facilities

Read facility selection from PuLP variables.

add_flow(origin: Any, destination: Any, volume: float, path: list | None = None) → None[source]

Add flow with path calculation using scipy network.

Parameters:
originAny

Origin node ID

destinationAny

Destination node ID

volumefloat

Flow volume

pathlist | None, default=None

Specific path to use (if None, shortest path is computed)

add_flows(flows: DataFrame | dict[tuple[Any, Any], float])[source]

Add multiple flows to the FRLM instance.

Parameters:
flowspd.DataFrame | dict[tuple[Any, Any], float]]

Flows to be added. Can be either:

  • A pandas DataFrame with flow information

  • A dictionary mapping (origin, destination) tuples to flow volumes

Returns:
selfFRLM

Returns the instance for method chaining

add_network(network: csr_matrix)[source]

Add network to the FRLM instance.

Parameters:
networkscipy.sparse.csr_matrix

The network as a scipy sparse matrix where element [i,j] represents the distance/cost between nodes i and j.

Returns:
selfFRLM

Returns the instance for method chaining

calculate_node_weights(include_destination: bool = False) → ndarray[source]

Calculate node weights based on flow volumes.

Parameters:
include_destinationbool, default=False

If True, include destination nodes in weight calculation. If False, only use origin nodes for weight calculation, as specified in the paper (Hong and Kuby, 2016).

Returns:
np.ndarray

Array of node weights

check_path_refueling_feasibility(path: list, facilities: list) → bool[source]

Check if a path can be traversed with given facilities using scipy network.

Parameters:
pathlist

Nodes in the path

facilitieslist

Potential refueling facilities

Returns:
bool

Whether the path is feasible with given facilities

compute_refueling_frequency(origin: Any, destination: Any) → float[source]
classmethod from_flow_dataframe(network: csr_matrix, flows: DataFrame | dict, **kwargs)[source]

Create FRLM instance from network and flows.

Parameters:
networksp.csr_matrix

Network as a scipy sparse matrix

flowspd.DataFrame | dict

Flow data

generate_path_refueling_combinations(facility_combinations: list[list] | None = None, start: int | None = None, stop: int | None = None, method: str = 'auto') → dict[source]

Generate dictionary mapping OD pairs to valid facility combinations.

Parameters:
facility_combinationslist[list]], optional

Pre-computed facility combinations (only used for combination method)

startint, optional

Minimum size of combinations (for combination method)

stopint, optional

Maximum size of combinations (for combination method)

methodstr, optional

Method to use: “auto”, “combination”, or “ac_pc”

  • “auto”: Automatically choose based on model type

  • “combination”: Generate all possible facility combinations

  • “ac_pc”: Generate K and a sets for Arc Cover Path Cover

Returns:
dict

Dictionary of OD pairs to valid facility combinations (combination method) or sets K and a sets (ac_pc method).

get_constraint_dual(constraint_name: str) → float | None[source]
get_reduced_costs() → dict[str, float][source]
get_shadow_price(constraint_name: str) → float[source]
get_shadow_prices() → dict[str, float][source]
get_slack(constraint_name: str) → float[source]
get_solver_details() → dict[source]

Retrieve detailed solver information.

Parameters:
verbosebool, default True

If True, print the details to console. If False, return details dictionary.

Returns:
dict

A dictionary containing detailed solver information

get_variable_value(var_name: str) → float[source]
get_variable_values() → dict[str, float][source]
is_constraint_active(constraint_name: str) → bool[source]
property problem

Return the PuLP problem instance.

property selected_facilities

Read facility selection from PuLP variables.

solve(solver: Literal['greedy'] | LpSolver = None, seed: int | None = None, initialization_method: str = 'empty', max_iterations: int = 100, **kwargs) → dict[source]

Solve the FRLM problem.

Parameters:
solverLiteral[“greedy”] | pulp.LpSolver]

Solver to use. If None, PuLP will use its default solver. If “greedy”, uses greedy heuristic. If a pulp.Solver instance, uses that solver.

seedint | None, default=None

Random seed for reproducibility

initialization_methodstr, default=”empty”

Method for initializing greedy solution

max_iterationsint, default=100

Maximum iterations for greedy solver

**kwargs

Additional solver-specific parameters

summary() → dict[source]

Generate a summary of the solution.

to_dataframes(include_iterations: bool = True) → dict[str, DataFrame][source]

Export solution to pandas DataFrames.

Parameters:
include_iterationsbool, default=True

Whether to include iteration details (for greedy solver)

Returns:
dict

Dictionary of DataFrames with keys:

  • ‘facilities’: Selected facilities and modules

  • ‘coverage’: Flow coverage details

  • ‘summary’: Summary statistics

  • ‘iterations’: Greedy solver iterations (if applicable)

  • ‘shadow_prices’: Shadow prices/Lagrange multipliers (if applicable)