def set_algorithm(self, algorithm: str): """ Chooses the assignment algorithm. e.g. 'frank-wolfe', 'bfw', 'msa' 'fw' is also accepted as an alternative to 'frank-wolfe' Args: algorithm (:obj:`list`): Algorithm to be used """ # First we instantiate the arrays we will be using over and over algo_dict = {i: i for i in self.all_algorithms} algo_dict["fw"] = "frank-wolfe" algo = algo_dict.get(algorithm.lower()) if algo is None: raise AttributeError( f"Assignment algorithm not available. Choose from: {','.join(self.all_algorithms)}" ) if algo == "all-or-nothing": self.assignment = allOrNothing(self) elif algo in ["msa", "frank-wolfe", "cfw", "bfw"]: self.assignment = LinearApproximation(self, algo) else: raise Exception("Algorithm not listed in the case selection") self.__dict__["algorithm"] = algo self.__collect_data()
def test_execute(self): # Loads and prepares the graph res1 = AssignmentResults() res1.prepare(self.g, self.matrix) assig1 = allOrNothing(self.matrix, self.g, res1) assig1.execute() res2 = AssignmentResults() res2.prepare(self.g, self.matrix2) assig2 = allOrNothing(self.matrix2, self.g, res2) assig2.execute() load1 = res1.get_load_results() load2 = res2.get_load_results() self.assertEqual(list(load1.matrix_tot * 2), list(load2.matrix_tot), "Something wrong with the AoN")
def test_skimming_on_assignment(self): res = AssignmentResults() res.prepare(self.g, self.matrix) self.g.set_skimming([]) self.g.set_blocked_centroid_flows(True) assig = allOrNothing(self.matrix, self.g, res) assig.execute() if res.skims.distance.sum() > 0: self.fail( "skimming for nothing during assignment returned something different than zero" ) res.prepare(self.g, self.matrix) assig = allOrNothing(self.matrix, self.g, res) assig.execute()
def set_algorithm(self, algorithm: str): """ Chooses the assignment algorithm. e.g. 'frank-wolfe', 'bfw', 'msa' """ # First we instantiate the arrays we will be using over and over if algorithm not in self.all_algorithms: raise AttributeError( f"Assignment algorithm not available. Choose from: {','.join(self.all_algorithms)}" ) if algorithm.lower() == "all-or-nothing": self.assignment = allOrNothing(self) elif algorithm.lower() in ["msa", "frank-wolfe", "cfw", "bfw"]: self.assignment = LinearApproximation(self, algorithm.lower()) else: raise Exception('Algorithm not listed in the case selection') self.__collect_data()
def execute(self): for c in self.traffic_classes: c.graph.set_graph(self.time_field) logger.info("{} Assignment STATS".format(self.algorithm)) logger.info("Iteration, RelativeGap, stepsize") for self.iter in range(1, self.max_iter + 1): if pyqt: self.equilibration.emit(['rgap', self.rgap]) self.equilibration.emit(['iterations', self.iter]) flows = [] aon_flows = [] for c in self.traffic_classes: aon = allOrNothing(c.matrix, c.graph, c._aon_results) if pyqt: aon.assignment.connect(self.signal_handler) aon.execute() c._aon_results.total_flows() aon_flows.append(c._aon_results.total_link_loads * c.pce) self.aon_total_flow = np.sum(aon_flows, axis=0) if self.iter == 1: for c in self.traffic_classes: copy_two_dimensions(c.results.link_loads, c._aon_results.link_loads, self.cores) c.results.total_flows() copy_one_dimension(c.results.total_link_loads, c._aon_results.total_link_loads, self.cores) if c.results.num_skims > 0: copy_three_dimensions(c.results.skims.matrix_view, c._aon_results.skims.matrix_view, self.cores) flows.append(c.results.total_link_loads * c.pce) else: self.__calculate_step_direction() self.calculate_stepsize() for c in self.traffic_classes: stp_dir = self.step_direction[c.mode] cls_res = c.results linear_combination(cls_res.link_loads, stp_dir.link_loads, cls_res.link_loads, self.stepsize, self.cores) if cls_res.num_skims > 0: linear_combination_skims(cls_res.skims.matrix_view, stp_dir.skims.matrix_view, cls_res.skims.matrix_view, self.stepsize, self.cores) cls_res.total_flows() flows.append(cls_res.total_link_loads * c.pce) self.fw_total_flow = np.sum(flows, axis=0) # Check convergence # This needs ot be done with the current costs, and not the future ones if self.iter > 1: if self.check_convergence(): if self.steps_below >= self.steps_below_needed_to_terminate: break else: self.steps_below += 1 self.vdf.apply_vdf(self.congested_time, self.fw_total_flow, self.capacity, self.free_flow_tt, *self.vdf_parameters) for c in self.traffic_classes: c.graph.cost = self.congested_time if self.time_field in c.graph.skim_fields: idx = c.graph.skim_fields.index(self.time_field) c.graph.skims[:, idx] = self.congested_time[:] c._aon_results.reset() logger.info("{},{},{}".format(self.iter, self.rgap, self.stepsize)) if self.rgap > self.rgap_target: logger.error("Desired RGap of {} was NOT reached".format( self.rgap_target)) logger.info( f"{self.algorithm} Assignment finished. {self.iter} iterations and {self.rgap} final gap" ) if pyqt: self.equilibration.emit(['rgap', self.rgap]) self.equilibration.emit(['iterations', self.iter]) self.equilibration.emit(['finished_threaded_procedure'])
def execute(self): for c in self.traffic_classes: c.graph.set_graph(self.time_field) logger.info(f"{self.algorithm} Assignment STATS") logger.info("Iteration, RelativeGap, stepsize") for self.iter in range(1, self.max_iter + 1): self.iteration_issue = [] if pyqt: self.equilibration.emit(["rgap", self.rgap]) self.equilibration.emit(["iterations", self.iter]) aon_flows = [] for c in self.traffic_classes: aon = allOrNothing(c.matrix, c.graph, c._aon_results) if pyqt: aon.assignment.connect(self.signal_handler) aon.execute() aon_flows.append(c._aon_results.total_link_loads * c.pce) self.aon_total_flow = np.sum(aon_flows, axis=0) flows = [] if self.iter == 1: for c in self.traffic_classes: copy_two_dimensions(c.results.link_loads, c._aon_results.link_loads, self.cores) copy_one_dimension(c.results.total_link_loads, c._aon_results.total_link_loads, self.cores) if c.results.num_skims > 0: copy_three_dimensions(c.results.skims.matrix_view, c._aon_results.skims.matrix_view, self.cores) flows.append(c.results.total_link_loads * c.pce) else: self.__calculate_step_direction() self.calculate_stepsize() for c in self.traffic_classes: stp_dir = self.step_direction[c.mode] cls_res = c.results linear_combination(cls_res.link_loads, stp_dir.link_loads, cls_res.link_loads, self.stepsize, self.cores) if cls_res.num_skims > 0: linear_combination_skims( cls_res.skims.matrix_view, stp_dir.skims.matrix_view, cls_res.skims.matrix_view, self.stepsize, self.cores, ) cls_res.total_flows() flows.append(cls_res.total_link_loads * c.pce) self.fw_total_flow = np.sum(flows, axis=0) # Check convergence # This needs to be done with the current costs, and not the future ones converged = False if self.iter > 1: converged = self.check_convergence() self.convergence_report["iteration"].append(self.iter) self.convergence_report["rgap"].append(self.rgap) self.convergence_report["warnings"].append("; ".join( self.iteration_issue)) self.convergence_report["alpha"].append(self.stepsize) if self.algorithm == "bfw": self.convergence_report["beta0"].append(self.betas[0]) self.convergence_report["beta1"].append(self.betas[1]) self.convergence_report["beta2"].append(self.betas[2]) logger.info(f"{self.iter},{self.rgap},{self.stepsize}") if converged: if self.steps_below >= self.steps_below_needed_to_terminate: break else: self.steps_below += 1 self.vdf.apply_vdf( self.congested_time, self.fw_total_flow, self.capacity, self.free_flow_tt, *self.vdf_parameters, self.cores, ) for c in self.traffic_classes: aggregate_link_costs(self.congested_time, c.graph.compact_cost, c.results.crosswalk) if self.time_field in c.graph.skim_fields: idx = c.graph.skim_fields.index(self.time_field) c.graph.skims[:, idx] = self.congested_time[:] c._aon_results.reset() if self.rgap > self.rgap_target: logger.error(f"Desired RGap of {self.rgap_target} was NOT reached") logger.info( f"{self.algorithm} Assignment finished. {self.iter} iterations and {self.rgap} final gap" ) if pyqt: self.equilibration.emit(["rgap", self.rgap]) self.equilibration.emit(["iterations", self.iter]) self.equilibration.emit(["finished_threaded_procedure"])
def execute(self): # We build the fixed cost field for c in self.traffic_classes: if c.fixed_cost_field: # divide fixed cost by volume-dependent prefactor (vot) such that we don't have to do it for # each occurence in the objective funtion. TODO: Need to think about cost skims here, we do # not want this there I think c.fixed_cost[c.graph.graph.__supernet_id__] = ( c.graph.graph[c.fixed_cost_field].values[:] * c.fc_multiplier / c.vot) c.fixed_cost[np.isnan(c.fixed_cost)] = 0 # TODO: Review how to eliminate this. It looks unnecessary # Just need to create some arrays for cost for c in self.traffic_classes: c.graph.set_graph(self.time_field) logger.info(f"{self.algorithm} Assignment STATS") logger.info("Iteration, RelativeGap, stepsize") for self.iter in range(1, self.max_iter + 1): self.iteration_issue = [] if pyqt: self.equilibration.emit(["rgap", self.rgap]) self.equilibration.emit(["iterations", self.iter]) aon_flows = [] self.__maybe_create_path_file_directories() for c in self.traffic_classes: # type: TrafficClass # cost = c.fixed_cost / c.vot + self.congested_time # now only once cost = c.fixed_cost + self.congested_time aggregate_link_costs(cost, c.graph.compact_cost, c.results.crosswalk) aon = allOrNothing(c.matrix, c.graph, c._aon_results) if pyqt: aon.assignment.connect(self.signal_handler) aon.execute() c._aon_results.link_loads *= c.pce c._aon_results.total_flows() aon_flows.append(c._aon_results.total_link_loads) self.aon_total_flow = np.sum(aon_flows, axis=0) flows = [] if self.iter == 1: for c in self.traffic_classes: copy_two_dimensions(c.results.link_loads, c._aon_results.link_loads, self.cores) c.results.total_flows() if c.results.num_skims > 0: copy_three_dimensions(c.results.skims.matrix_view, c._aon_results.skims.matrix_view, self.cores) flows.append(c.results.total_link_loads) if self.algorithm == "all-or-nothing": break else: self.__calculate_step_direction() self.calculate_stepsize() for c in self.traffic_classes: stp_dir = self.step_direction[c.__id__] cls_res = c.results linear_combination(cls_res.link_loads, stp_dir.link_loads, cls_res.link_loads, self.stepsize, self.cores) if cls_res.num_skims > 0: linear_combination_skims( cls_res.skims.matrix_view, stp_dir.skims.matrix_view, cls_res.skims.matrix_view, self.stepsize, self.cores, ) cls_res.total_flows() flows.append(cls_res.total_link_loads) self.fw_total_flow = np.sum(flows, axis=0) # Check convergence # This needs to be done with the current costs, and not the future ones converged = self.check_convergence() if self.iter > 1 else False self.vdf.apply_vdf( self.congested_time, self.fw_total_flow, self.capacity, self.free_flow_tt, *self.vdf_parameters, self.cores, ) self.convergence_report["iteration"].append(self.iter) self.convergence_report["rgap"].append(self.rgap) self.convergence_report["warnings"].append("; ".join( self.iteration_issue)) self.convergence_report["alpha"].append(self.stepsize) if self.algorithm in ["cfw", "bfw"]: self.convergence_report["beta0"].append(self.betas[0]) self.convergence_report["beta1"].append(self.betas[1]) self.convergence_report["beta2"].append(self.betas[2]) for c in self.traffic_classes: c._aon_results.reset() if self.time_field not in c.graph.skim_fields: continue idx = c.graph.skim_fields.index(self.time_field) c.graph.skims[:, idx] = self.congested_time[:] logger.info(f"{self.iter},{self.rgap},{self.stepsize}") if converged: self.steps_below += 1 if self.steps_below >= self.steps_below_needed_to_terminate: break else: self.steps_below = 0 for c in self.traffic_classes: c.results.link_loads /= c.pce c.results.total_flows() # TODO (Jan 18/4/21): Do we want to blob store path files (by iteration, class, origin, destination) in sqlite? # or do we just use one big hdf5 file? if (self.rgap > self.rgap_target) and (self.algorithm != "all-or-nothing"): logger.error(f"Desired RGap of {self.rgap_target} was NOT reached") logger.info( f"{self.algorithm} Assignment finished. {self.iter} iterations and {self.rgap} final gap" ) if pyqt: self.equilibration.emit(["rgap", self.rgap]) self.equilibration.emit(["iterations", self.iter]) self.equilibration.emit(["finished_threaded_procedure"])
def execute(self): for c in self.traffic_classes: c.graph.set_graph(self.time_field) logger.info("{} Assignment STATS".format(self.algorithm)) logger.info("Iteration, RelativeGap, stepsize") for self.iter in range(1, self.max_iter + 1): flows = [] aon_flows = [] for c in self.traffic_classes: aon = allOrNothing(c.matrix, c.graph, c._aon_results) aon.execute() c._aon_results.total_flows() aon_flows.append(c._aon_results.total_link_loads * c.pce) self.aon_total_flow = np.sum(aon_flows, axis=0) if self.iter == 1: for c in self.traffic_classes: copy_two_dimensions(c.results.link_loads, c._aon_results.link_loads, self.cores) c.results.total_flows() copy_one_dimension(c.results.total_link_loads, c._aon_results.total_link_loads, self.cores) if c.results.num_skims > 0: copy_three_dimensions(c.results.skims.matrix_view, c._aon_results.skims.matrix_view, self.cores) flows.append(c.results.total_link_loads * c.pce) else: self.__calculate_step_direction() self.calculate_stepsize() for c in self.traffic_classes: stp_dir = self.step_direction[c.mode] cls_res = c.results linear_combination(cls_res.link_loads, stp_dir.link_loads, cls_res.link_loads, self.stepsize, self.cores) # TODO: We need to compute the step direction for skims as well. # It is probably a matter of transforming the step_direction values from numpy arrays to # full AssignmentResults() ones, and cleaning the stuff we don't need if cls_res.num_skims > 0: linear_combination_skims(cls_res.skims.matrix_view, stp_dir.skims.matrix_view, cls_res.skims.matrix_view, self.stepsize, self.cores) cls_res.total_flows() flows.append(cls_res.total_link_loads * c.pce) self.fw_total_flow = np.sum(flows, axis=0) # Check convergence # This needs ot be done with the current costs, and not the future ones if self.iter > 1: if self.check_convergence(): if self.steps_below >= self.steps_below_needed_to_terminate: break else: self.steps_below += 1 self.vdf.apply_vdf( self.congested_time, self.fw_total_flow, self.capacity, self.free_flow_tt, *self.vdf_parameters ) for c in self.traffic_classes: c.graph.cost = self.congested_time c._aon_results.reset() logger.info("{},{},{}".format(self.iter, self.rgap, self.stepsize)) if self.rgap > self.rgap_target: logger.error("Desired RGap of {} was NOT reached".format(self.rgap_target)) logger.info( "{} Assignment finished. {} iterations and {} final gap".format(self.algorithm, self.iter, self.rgap) )