Skip to content

Commit

Permalink
Allow select link loading to be disabled
Browse files Browse the repository at this point in the history
  • Loading branch information
Jake-Moss committed Aug 8, 2024
1 parent 0ecf145 commit 119b283
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ cdef class LinkLoadingResults:
GeneralisedCOODemand demand
readonly object select_link_set_names
size_t num_links
bint sl_link_loading

# Number of threads
# * number of demand cols
Expand Down
95 changes: 56 additions & 39 deletions aequilibrae/paths/cython/route_choice_link_loading_results.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ cdef class LinkLoadingResults:
demand: GeneralisedCOODemand,
select_links: Dict[Hashable, FrozenSet[FrozenSet[int]]],
num_links: int,
sl_link_loading: bool,
threads: int
):
if threads <= 0:
Expand All @@ -28,6 +29,7 @@ cdef class LinkLoadingResults:
self.demand = demand
self.num_links = num_links
self.od_matrix_objects = None
self.sl_link_loading = sl_link_loading

cdef:
vector[unique_ptr[vector[double]]] *f64_demand_cols
Expand Down Expand Up @@ -94,39 +96,40 @@ cdef class LinkLoadingResults:
vector[unique_ptr[vector[double]]] *f64_sl_demand_cols
vector[unique_ptr[vector[float]]] *f32_sl_demand_cols

# Allocate f64 thread storage for select link
self.f64_sl_link_loading_threaded.reserve(threads)
for i in range(threads):
f64_sl_select_link_sets = new vector[unique_ptr[vector[unique_ptr[vector[double]]]]]()
f64_sl_select_link_sets.reserve(self.select_link_sets.size())
if self.sl_link_loading:
# Allocate f64 thread storage for select link
self.f64_sl_link_loading_threaded.reserve(threads)
for i in range(threads):
f64_sl_select_link_sets = new vector[unique_ptr[vector[unique_ptr[vector[double]]]]]()
f64_sl_select_link_sets.reserve(self.select_link_sets.size())

for j in range(self.select_link_sets.size()):
f64_sl_demand_cols = new vector[unique_ptr[vector[double]]]()
f64_sl_demand_cols.reserve(len(self.demand.f64_names))
for j in range(self.select_link_sets.size()):
f64_sl_demand_cols = new vector[unique_ptr[vector[double]]]()
f64_sl_demand_cols.reserve(len(self.demand.f64_names))

for k in range(len(self.demand.f64_names)):
f64_sl_demand_cols.emplace_back(new vector[double](self.num_links))
for k in range(len(self.demand.f64_names)):
f64_sl_demand_cols.emplace_back(new vector[double](self.num_links))

f64_sl_select_link_sets.emplace_back(f64_sl_demand_cols)
f64_sl_select_link_sets.emplace_back(f64_sl_demand_cols)

self.f64_sl_link_loading_threaded.emplace_back(f64_sl_select_link_sets)
self.f64_sl_link_loading_threaded.emplace_back(f64_sl_select_link_sets)

# Allocate f32 thread storage for select link
self.f32_sl_link_loading_threaded.reserve(threads)
for i in range(threads):
f32_sl_select_link_sets = new vector[unique_ptr[vector[unique_ptr[vector[float]]]]]()
f32_sl_select_link_sets.reserve(self.select_link_sets.size())
# Allocate f32 thread storage for select link
self.f32_sl_link_loading_threaded.reserve(threads)
for i in range(threads):
f32_sl_select_link_sets = new vector[unique_ptr[vector[unique_ptr[vector[float]]]]]()
f32_sl_select_link_sets.reserve(self.select_link_sets.size())

for j in range(self.select_link_sets.size()):
f32_sl_demand_cols = new vector[unique_ptr[vector[float]]]()
f32_sl_demand_cols.reserve(len(self.demand.f32_names))
for j in range(self.select_link_sets.size()):
f32_sl_demand_cols = new vector[unique_ptr[vector[float]]]()
f32_sl_demand_cols.reserve(len(self.demand.f32_names))

for k in range(len(self.demand.f32_names)):
f32_sl_demand_cols.emplace_back(new vector[float](self.num_links))
for k in range(len(self.demand.f32_names)):
f32_sl_demand_cols.emplace_back(new vector[float](self.num_links))

f32_sl_select_link_sets.emplace_back(f32_sl_demand_cols)
f32_sl_select_link_sets.emplace_back(f32_sl_demand_cols)

self.f32_sl_link_loading_threaded.emplace_back(f32_sl_select_link_sets)
self.f32_sl_link_loading_threaded.emplace_back(f32_sl_select_link_sets)

# self.f64_sl_link_loading and self.f32_sl_link_loading are not allocated here. The objects are initialised to
# empty vectors but elements are created in self.reduce_sl_link_loading
Expand Down Expand Up @@ -181,6 +184,9 @@ cdef class LinkLoadingResults:
return self.link_loading_objects

cdef object sl_link_loading_to_objects(self, long long[:] compressed_id_view, int cores):
if not self.sl_link_loading:
return {}

if self.sl_link_loading_objects is None:
results = []
for i in range(self.select_link_sets.size()):
Expand Down Expand Up @@ -414,21 +420,27 @@ cdef class LinkLoadingResults:
cdef:
# Cython doesn't allow declaring references to objects outside of function signatures. So we get the raw
# pointer instead. It is still owned by the unique_ptr.
vector[unique_ptr[vector[unique_ptr[vector[double]]]]] *f64_ll_sets_cols = \
self.f64_sl_link_loading_threaded[thread_id].get()
vector[unique_ptr[vector[unique_ptr[vector[float]]]]] *f32_ll_sets_cols = \
self.f32_sl_link_loading_threaded[thread_id].get()
vector[unique_ptr[vector[COO_f64_struct]]] *f64_od_sets_cols = \
self.f64_sl_od_matrix_threaded[thread_id].get()
vector[unique_ptr[vector[COO_f32_struct]]] *f32_od_sets_cols = \
self.f32_sl_od_matrix_threaded[thread_id].get()
vector[unique_ptr[vector[unique_ptr[vector[double]]]]] *f64_ll_sets_cols
vector[unique_ptr[vector[unique_ptr[vector[float]]]]] *f32_ll_sets_cols
vector[unique_ptr[vector[COO_f64_struct]]] *f64_od_sets_cols
vector[unique_ptr[vector[COO_f32_struct]]] *f32_od_sets_cols
vector[double] *f64_ll
vector[float] *f32_ll

double f64_load
float f32_load
size_t i, j, k

if self.sl_link_loading:
f64_ll_sets_cols = self.f64_sl_link_loading_threaded[thread_id].get()
f32_ll_sets_cols = self.f32_sl_link_loading_threaded[thread_id].get()
else:
f64_ll_sets_cols = NULL
f32_ll_sets_cols = NULL

f64_od_sets_cols = self.f64_sl_od_matrix_threaded[thread_id].get()
f32_od_sets_cols = self.f32_sl_od_matrix_threaded[thread_id].get()

# For each select link set
for i in range(self.select_link_sets.size()):
# for each route in the route set
Expand All @@ -449,12 +461,13 @@ cdef class LinkLoadingResults:
if f64_load == 0.0:
continue

f64_ll = d(d(f64_ll_sets_cols)[i])[k].get()
COO.f64_struct_append(d(d(f64_od_sets_cols)[i])[k], origin_idx, dest_idx, f64_load)

# then apply that to every link in the route
for link in d(route_set[j]):
d(f64_ll)[link] = d(f64_ll)[link] + f64_load
if self.sl_link_loading:
f64_ll = d(d(f64_ll_sets_cols)[i])[k].get()
# then apply that to every link in the route
for link in d(route_set[j]):
d(f64_ll)[link] = d(f64_ll)[link] + f64_load

# then we do it again for f32
for k in range(self.demand.f32.size()):
Expand All @@ -463,11 +476,12 @@ cdef class LinkLoadingResults:
if f32_load == 0.0:
continue

f32_ll = d(d(f32_ll_sets_cols)[i])[k].get()
COO.f32_struct_append(d(d(f32_od_sets_cols)[i])[k], origin_idx, dest_idx, f32_load)

for link in d(route_set[j]):
d(f32_ll)[link] = d(f32_ll)[link] + f32_load
if self.sl_link_loading:
f32_ll = d(d(f32_ll_sets_cols)[i])[k].get()
for link in d(route_set[j]):
d(f32_ll)[link] = d(f32_ll)[link] + f32_load

@cython.wraparound(False)
@cython.embedsignature(True)
Expand All @@ -490,6 +504,9 @@ cdef class LinkLoadingResults:

size_t thread_id, i, j

if not self.sl_link_loading:
return

# Allocate the result link loads
self.f64_sl_link_loading.reserve(self.select_link_sets.size())
for i in range(self.select_link_sets.size()):
Expand Down
3 changes: 2 additions & 1 deletion aequilibrae/paths/cython/route_choice_set.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ cdef class RouteChoiceSet:
self,
demand: GeneralisedCOODemand,
select_links: Dict[str, FrozenSet[FrozenSet[int]]] = None,
sl_link_loading: bool = True,
max_routes: int = 0,
max_depth: int = 0,
max_misses: int = 100,
Expand Down Expand Up @@ -261,7 +262,7 @@ cdef class RouteChoiceSet:
int thread_id

demand._initalise_col_names()
self.ll_results = LinkLoadingResults(demand, select_links, self.num_links, c_cores)
self.ll_results = LinkLoadingResults(demand, select_links, self.num_links, sl_link_loading, c_cores)

for _, grouped_demand_df in (demand.batches() if where is not None else ((None, None),)):
demand._initalise_c_data(grouped_demand_df)
Expand Down
16 changes: 14 additions & 2 deletions aequilibrae/paths/route_choice.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def __init__(self, graph: Graph, project=None):

self._config = {}
self._selected_links = {}
self.sl_link_loading = True

@cached_property
def __rc(self) -> RouteChoiceSet:
Expand Down Expand Up @@ -262,6 +263,7 @@ def execute_single(self, origin: int, destination: int, demand: float = 0.0) ->
path_size_logit=bool(demand),
cores=self.cores,
where=str(self.where) if self.where is not None else None,
sl_link_loading=self.sl_link_loading,
**self.parameters,
)

Expand Down Expand Up @@ -289,6 +291,7 @@ def execute(self, perform_assignment: bool = True) -> None:
path_size_logit=perform_assignment,
cores=self.cores,
where=str(self.where) if self.where is not None else None,
sl_link_loading=self.sl_link_loading,
**self.parameters,
)

Expand Down Expand Up @@ -380,7 +383,9 @@ def __link_loads_to_df(self, mapping, lids, link_loads):
df.columns = pd.MultiIndex.from_tuples(df.columns)
return df.sort_index()

def set_select_links(self, links: Dict[Hashable, List[Union[Tuple[int, int], List[Tuple[int, int]]]]]):
def set_select_links(
self, links: Dict[Hashable, List[Union[Tuple[int, int], List[Tuple[int, int]]]]], link_loading=True
):
"""
Set the selected links. Checks if the links and directions are valid. Supports OR and AND sets of links.
Expand All @@ -395,8 +400,13 @@ def set_select_links(self, links: Dict[Hashable, List[Union[Tuple[int, int], Lis
:Arguments:
**links** (:obj:`Union[None, Dict[Hashable, List[Union[Tuple[int, int], List[Tuple[int, int]]]]]]`):
Name of link set and Link IDs and directions to be used in select link analysis.
**link_loading** (:obj:`bool`): Enable select link loading. If disabled only OD matrix results are
available.
"""
self._selected_links = {}
self.sl_link_loading = link_loading

if links is None:
del self._config["select_links"]
Expand Down Expand Up @@ -460,7 +470,9 @@ def get_select_link_loading_results(self) -> pd.DataFrame:
"""

if self.demand.no_demand():
raise ValueError("No demand was provided. To perform link loading add a demand matrix or data frame")
raise ValueError("no demand was provided. To perform link loading add a demand matrix or data frame")
elif not self.sl_link_loading:
raise ValueError("select link loading was disabled via `set_select_links(..., link_loading=False)`")

sl_link_loads = {}
for sl_name, sl_res in self.__rc.get_sl_link_loading().items():
Expand Down

0 comments on commit 119b283

Please sign in to comment.