// r_c_shortest_paths.hpp header file // Copyright Michael Drexl 2005, 2006. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://boost.org/LICENSE_1_0.txt) #ifndef BOOST_GRAPH_R_C_SHORTEST_PATHS_HPP #define BOOST_GRAPH_R_C_SHORTEST_PATHS_HPP #include #include #include #include #include #include #include #include #include namespace boost { // r_c_shortest_paths_label struct template struct r_c_shortest_paths_label : public boost::enable_shared_from_this > { r_c_shortest_paths_label ( const unsigned long n, const Resource_Container& rc = Resource_Container(), const boost::shared_ptr > pl = boost::shared_ptr >(), const typename graph_traits::edge_descriptor& ed = graph_traits::edge_descriptor(), const typename graph_traits::vertex_descriptor& vd = graph_traits::vertex_descriptor() ) : num( n ), cumulated_resource_consumption( rc ), p_pred_label( pl ), pred_edge( ed ), resident_vertex( vd ), b_is_dominated( false ), b_is_processed( false ) {} r_c_shortest_paths_label& operator=( const r_c_shortest_paths_label& other ) { if( this == &other ) return *this; this->~r_c_shortest_paths_label(); new( this ) r_c_shortest_paths_label( other ); return *this; } const unsigned long num; Resource_Container cumulated_resource_consumption; const boost::shared_ptr > p_pred_label; const typename graph_traits::edge_descriptor pred_edge; const typename graph_traits::vertex_descriptor resident_vertex; bool b_is_dominated; bool b_is_processed; }; // r_c_shortest_paths_label template inline bool operator== ( const r_c_shortest_paths_label& l1, const r_c_shortest_paths_label& l2 ) { return l1.cumulated_resource_consumption == l2.cumulated_resource_consumption; } template inline bool operator!= ( const r_c_shortest_paths_label& l1, const r_c_shortest_paths_label& l2 ) { return !( l1 == l2 ); } template inline bool operator< ( const r_c_shortest_paths_label& l1, const r_c_shortest_paths_label& l2 ) { return l1.cumulated_resource_consumption < l2.cumulated_resource_consumption; } template inline bool operator> ( const r_c_shortest_paths_label& l1, const r_c_shortest_paths_label& l2 ) { return l2.cumulated_resource_consumption < l1.cumulated_resource_consumption; } template inline bool operator<= ( const r_c_shortest_paths_label& l1, const r_c_shortest_paths_label& l2 ) { return l1 < l2 || l1 == l2; } template inline bool operator>= ( const r_c_shortest_paths_label& l1, const r_c_shortest_paths_label& l2 ) { return l2 < l1 || l1 == l2; } template inline bool operator< ( const boost::shared_ptr > &t, const boost::shared_ptr > &u) { return *t < *u; } template inline bool operator<=( const boost::shared_ptr > &t, const boost::shared_ptr > &u ) { return *t <= *u; } template inline bool operator> ( const boost::shared_ptr > &t, const boost::shared_ptr > &u ) { return *t > *u; } template inline bool operator>= ( const boost::shared_ptr > &t, const boost::shared_ptr > &u) { return *t >= *u; } namespace detail { // r_c_shortest_paths_dispatch function (body/implementation) template void r_c_shortest_paths_dispatch ( const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& /*edge_index_map*/, typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, // each inner vector corresponds to a pareto-optimal path std::vector ::edge_descriptor> >& pareto_optimal_solutions, std::vector & pareto_optimal_resource_containers, bool b_all_pareto_optimal_solutions, // to initialize the first label/resource container // and to carry the type information const Resource_Container& rc, Resource_Extension_Function& ref, Dominance_Function& dominance, // to specify the memory management strategy for the labels Label_Allocator /*la*/, Visitor vis ) { pareto_optimal_resource_containers.clear(); pareto_optimal_solutions.clear(); size_t i_label_num = 0; #if defined(BOOST_NO_CXX11_ALLOCATOR) typedef typename Label_Allocator::template rebind >::other LAlloc; #else typedef typename std::allocator_traits::template rebind_alloc > LAlloc; typedef std::allocator_traits LTraits; #endif LAlloc l_alloc; typedef boost::shared_ptr > Splabel; std::priority_queue, std::greater > unprocessed_labels; bool b_feasible = true; Splabel splabel_first_label = boost::allocate_shared >( l_alloc, i_label_num++, rc, boost::shared_ptr >(), typename graph_traits::edge_descriptor(), s ); unprocessed_labels.push( splabel_first_label ); std::vector > vec_vertex_labels_data( num_vertices( g ) ); iterator_property_map >::iterator, VertexIndexMap> vec_vertex_labels(vec_vertex_labels_data.begin(), vertex_index_map); vec_vertex_labels[s].push_back( splabel_first_label ); typedef std::vector::iterator> vec_last_valid_positions_for_dominance_data_type; vec_last_valid_positions_for_dominance_data_type vec_last_valid_positions_for_dominance_data( num_vertices( g ) ); iterator_property_map< typename vec_last_valid_positions_for_dominance_data_type::iterator, VertexIndexMap> vec_last_valid_positions_for_dominance (vec_last_valid_positions_for_dominance_data.begin(), vertex_index_map); BGL_FORALL_VERTICES_T(v, g, Graph) { put(vec_last_valid_positions_for_dominance, v, vec_vertex_labels[v].begin()); } std::vector vec_last_valid_index_for_dominance_data( num_vertices( g ), 0 ); iterator_property_map::iterator, VertexIndexMap> vec_last_valid_index_for_dominance (vec_last_valid_index_for_dominance_data.begin(), vertex_index_map); std::vector b_vec_vertex_already_checked_for_dominance_data( num_vertices( g ), false ); iterator_property_map::iterator, VertexIndexMap> b_vec_vertex_already_checked_for_dominance (b_vec_vertex_already_checked_for_dominance_data.begin(), vertex_index_map); while( !unprocessed_labels.empty() && vis.on_enter_loop(unprocessed_labels, g) ) { Splabel cur_label = unprocessed_labels.top(); unprocessed_labels.pop(); vis.on_label_popped( *cur_label, g ); // an Splabel object in unprocessed_labels and the respective Splabel // object in the respective list of vec_vertex_labels share their // embedded r_c_shortest_paths_label object // to avoid memory leaks, dominated // r_c_shortest_paths_label objects are marked and deleted when popped // from unprocessed_labels, as they can no longer be deleted at the end of // the function; only the Splabel object in unprocessed_labels still // references the r_c_shortest_paths_label object // this is also for efficiency, because the else branch is executed only // if there is a chance that extending the // label leads to new undominated labels, which in turn is possible only // if the label to be extended is undominated if( !cur_label->b_is_dominated ) { typename boost::graph_traits::vertex_descriptor i_cur_resident_vertex = cur_label->resident_vertex; std::list& list_labels_cur_vertex = get(vec_vertex_labels, i_cur_resident_vertex); if( list_labels_cur_vertex.size() >= 2 && vec_last_valid_index_for_dominance[i_cur_resident_vertex] < list_labels_cur_vertex.size() ) { typename std::list::iterator outer_iter = list_labels_cur_vertex.begin(); bool b_outer_iter_at_or_beyond_last_valid_pos_for_dominance = false; while( outer_iter != list_labels_cur_vertex.end() ) { Splabel cur_outer_splabel = *outer_iter; typename std::list::iterator inner_iter = outer_iter; if( !b_outer_iter_at_or_beyond_last_valid_pos_for_dominance && outer_iter == get(vec_last_valid_positions_for_dominance, i_cur_resident_vertex) ) b_outer_iter_at_or_beyond_last_valid_pos_for_dominance = true; if( !get(b_vec_vertex_already_checked_for_dominance, i_cur_resident_vertex) || b_outer_iter_at_or_beyond_last_valid_pos_for_dominance ) { ++inner_iter; } else { inner_iter = get(vec_last_valid_positions_for_dominance, i_cur_resident_vertex); ++inner_iter; } bool b_outer_iter_erased = false; while( inner_iter != list_labels_cur_vertex.end() ) { Splabel cur_inner_splabel = *inner_iter; if( dominance( cur_outer_splabel-> cumulated_resource_consumption, cur_inner_splabel-> cumulated_resource_consumption ) ) { typename std::list::iterator buf = inner_iter; ++inner_iter; list_labels_cur_vertex.erase( buf ); if( cur_inner_splabel->b_is_processed ) { cur_inner_splabel.reset(); } else cur_inner_splabel->b_is_dominated = true; continue; } else ++inner_iter; if( dominance( cur_inner_splabel-> cumulated_resource_consumption, cur_outer_splabel-> cumulated_resource_consumption ) ) { typename std::list::iterator buf = outer_iter; ++outer_iter; list_labels_cur_vertex.erase( buf ); b_outer_iter_erased = true; if( cur_outer_splabel->b_is_processed ) { cur_outer_splabel.reset(); } else cur_outer_splabel->b_is_dominated = true; break; } } if( !b_outer_iter_erased ) ++outer_iter; } if( list_labels_cur_vertex.size() > 1 ) put(vec_last_valid_positions_for_dominance, i_cur_resident_vertex, (--(list_labels_cur_vertex.end()))); else put(vec_last_valid_positions_for_dominance, i_cur_resident_vertex, list_labels_cur_vertex.begin()); put(b_vec_vertex_already_checked_for_dominance, i_cur_resident_vertex, true); put(vec_last_valid_index_for_dominance, i_cur_resident_vertex, list_labels_cur_vertex.size() - 1); } } if( !b_all_pareto_optimal_solutions && cur_label->resident_vertex == t ) { // the devil don't sleep if( cur_label->b_is_dominated ) { cur_label.reset(); } while( unprocessed_labels.size() ) { Splabel l = unprocessed_labels.top(); unprocessed_labels.pop(); // delete only dominated labels, because nondominated labels are // deleted at the end of the function if( l->b_is_dominated ) { l.reset(); } } break; } if( !cur_label->b_is_dominated ) { cur_label->b_is_processed = true; vis.on_label_not_dominated( *cur_label, g ); typename graph_traits::vertex_descriptor cur_vertex = cur_label->resident_vertex; typename graph_traits::out_edge_iterator oei, oei_end; for( boost::tie( oei, oei_end ) = out_edges( cur_vertex, g ); oei != oei_end; ++oei ) { b_feasible = true; Splabel new_label = boost::allocate_shared >( l_alloc, i_label_num++, cur_label->cumulated_resource_consumption, cur_label, *oei, target( *oei, g ) ); b_feasible = ref( g, new_label->cumulated_resource_consumption, new_label->p_pred_label->cumulated_resource_consumption, new_label->pred_edge ); if( !b_feasible ) { vis.on_label_not_feasible( *new_label, g ); new_label.reset(); } else { vis.on_label_feasible( *new_label, g ); vec_vertex_labels[new_label->resident_vertex]. push_back( new_label ); unprocessed_labels.push( new_label ); } } } else { vis.on_label_dominated( *cur_label, g ); cur_label.reset(); } } std::list dsplabels = get(vec_vertex_labels, t); typename std::list::const_iterator csi = dsplabels.begin(); typename std::list::const_iterator csi_end = dsplabels.end(); // if d could be reached from o if( !dsplabels.empty() ) { for( ; csi != csi_end; ++csi ) { std::vector::edge_descriptor> cur_pareto_optimal_path; boost::shared_ptr > p_cur_label = *csi; pareto_optimal_resource_containers. push_back( p_cur_label->cumulated_resource_consumption ); while( p_cur_label->num != 0 ) { cur_pareto_optimal_path.push_back( p_cur_label->pred_edge ); p_cur_label = p_cur_label->p_pred_label; // assertion b_is_valid beyond this point is not correct if the domination function // requires resource levels to be strictly greater than existing values // // Example // Customers // id min_arrival max_departure // 2 0 974 // 3 0 972 // 4 0 964 // 5 678 801 // // Path A: 2-3-4-5 (times: 0-16-49-84-678) // Path B: 3-2-4-5 (times: 0-18-51-62-678) // The partial path 3-2-4 dominates the other partial path 2-3-4, // though the path 3-2-4-5 does not strictly dominate the path 2-3-4-5 } pareto_optimal_solutions.push_back( cur_pareto_optimal_path ); if( !b_all_pareto_optimal_solutions ) break; } } BGL_FORALL_VERTICES_T(i, g, Graph) { std::list& list_labels_cur_vertex = vec_vertex_labels[i]; typename std::list::iterator si = list_labels_cur_vertex.begin(); const typename std::list::iterator si_end = list_labels_cur_vertex.end(); for(; si != si_end; ++si ) { (*si).reset(); } } } // r_c_shortest_paths_dispatch } // detail // default_r_c_shortest_paths_visitor struct struct default_r_c_shortest_paths_visitor { template void on_label_popped( const Label&, const Graph& ) {} template void on_label_feasible( const Label&, const Graph& ) {} template void on_label_not_feasible( const Label&, const Graph& ) {} template void on_label_dominated( const Label&, const Graph& ) {} template void on_label_not_dominated( const Label&, const Graph& ) {} template bool on_enter_loop(const Queue& queue, const Graph& graph) {return true;} }; // default_r_c_shortest_paths_visitor // default_r_c_shortest_paths_allocator typedef std::allocator default_r_c_shortest_paths_allocator; // default_r_c_shortest_paths_allocator // r_c_shortest_paths functions (handle/interface) // first overload: // - return all pareto-optimal solutions // - specify Label_Allocator and Visitor arguments template void r_c_shortest_paths ( const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& edge_index_map, typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, // each inner vector corresponds to a pareto-optimal path std::vector::edge_descriptor> >& pareto_optimal_solutions, std::vector& pareto_optimal_resource_containers, // to initialize the first label/resource container // and to carry the type information const Resource_Container& rc, const Resource_Extension_Function& ref, const Dominance_Function& dominance, // to specify the memory management strategy for the labels Label_Allocator la, Visitor vis ) { r_c_shortest_paths_dispatch( g, vertex_index_map, edge_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, true, rc, ref, dominance, la, vis ); } // second overload: // - return only one pareto-optimal solution // - specify Label_Allocator and Visitor arguments template void r_c_shortest_paths ( const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& edge_index_map, typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, std::vector::edge_descriptor>& pareto_optimal_solution, Resource_Container& pareto_optimal_resource_container, // to initialize the first label/resource container // and to carry the type information const Resource_Container& rc, const Resource_Extension_Function& ref, const Dominance_Function& dominance, // to specify the memory management strategy for the labels Label_Allocator la, Visitor vis ) { // each inner vector corresponds to a pareto-optimal path std::vector::edge_descriptor> > pareto_optimal_solutions; std::vector pareto_optimal_resource_containers; r_c_shortest_paths_dispatch( g, vertex_index_map, edge_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, false, rc, ref, dominance, la, vis ); if (!pareto_optimal_solutions.empty()) { pareto_optimal_solution = pareto_optimal_solutions[0]; pareto_optimal_resource_container = pareto_optimal_resource_containers[0]; } } // third overload: // - return all pareto-optimal solutions // - use default Label_Allocator and Visitor template void r_c_shortest_paths ( const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& edge_index_map, typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, // each inner vector corresponds to a pareto-optimal path std::vector::edge_descriptor> >& pareto_optimal_solutions, std::vector& pareto_optimal_resource_containers, // to initialize the first label/resource container // and to carry the type information const Resource_Container& rc, const Resource_Extension_Function& ref, const Dominance_Function& dominance ) { r_c_shortest_paths_dispatch( g, vertex_index_map, edge_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, true, rc, ref, dominance, default_r_c_shortest_paths_allocator(), default_r_c_shortest_paths_visitor() ); } // fourth overload: // - return only one pareto-optimal solution // - use default Label_Allocator and Visitor template void r_c_shortest_paths ( const Graph& g, const VertexIndexMap& vertex_index_map, const EdgeIndexMap& edge_index_map, typename graph_traits::vertex_descriptor s, typename graph_traits::vertex_descriptor t, std::vector::edge_descriptor>& pareto_optimal_solution, Resource_Container& pareto_optimal_resource_container, // to initialize the first label/resource container // and to carry the type information const Resource_Container& rc, const Resource_Extension_Function& ref, const Dominance_Function& dominance ) { // each inner vector corresponds to a pareto-optimal path std::vector::edge_descriptor> > pareto_optimal_solutions; std::vector pareto_optimal_resource_containers; r_c_shortest_paths_dispatch( g, vertex_index_map, edge_index_map, s, t, pareto_optimal_solutions, pareto_optimal_resource_containers, false, rc, ref, dominance, default_r_c_shortest_paths_allocator(), default_r_c_shortest_paths_visitor() ); if (!pareto_optimal_solutions.empty()) { pareto_optimal_solution = pareto_optimal_solutions[0]; pareto_optimal_resource_container = pareto_optimal_resource_containers[0]; } } // r_c_shortest_paths // check_r_c_path function template void check_r_c_path( const Graph& g, const std::vector ::edge_descriptor>& ed_vec_path, const Resource_Container& initial_resource_levels, // if true, computed accumulated final resource levels must // be equal to desired_final_resource_levels // if false, computed accumulated final resource levels must // be less than or equal to desired_final_resource_levels bool b_result_must_be_equal_to_desired_final_resource_levels, const Resource_Container& desired_final_resource_levels, Resource_Container& actual_final_resource_levels, const Resource_Extension_Function& ref, bool& b_is_a_path_at_all, bool& b_feasible, bool& b_correctly_extended, typename graph_traits::edge_descriptor& ed_last_extended_arc ) { size_t i_size_ed_vec_path = ed_vec_path.size(); std::vector::edge_descriptor> buf_path; if( i_size_ed_vec_path == 0 ) b_feasible = true; else { if( i_size_ed_vec_path == 1 || target( ed_vec_path[0], g ) == source( ed_vec_path[1], g ) ) buf_path = ed_vec_path; else for( size_t i = i_size_ed_vec_path ; i > 0; --i ) buf_path.push_back( ed_vec_path[i - 1] ); for( size_t i = 0; i < i_size_ed_vec_path - 1; ++i ) { if( target( buf_path[i], g ) != source( buf_path[i + 1], g ) ) { b_is_a_path_at_all = false; b_feasible = false; b_correctly_extended = false; return; } } } b_is_a_path_at_all = true; b_feasible = true; b_correctly_extended = false; Resource_Container current_resource_levels = initial_resource_levels; actual_final_resource_levels = current_resource_levels; for( size_t i = 0; i < i_size_ed_vec_path; ++i ) { ed_last_extended_arc = buf_path[i]; b_feasible = ref( g, actual_final_resource_levels, current_resource_levels, buf_path[i] ); current_resource_levels = actual_final_resource_levels; if( !b_feasible ) return; } if( b_result_must_be_equal_to_desired_final_resource_levels ) b_correctly_extended = actual_final_resource_levels == desired_final_resource_levels ? true : false; else { if( actual_final_resource_levels < desired_final_resource_levels || actual_final_resource_levels == desired_final_resource_levels ) b_correctly_extended = true; } } // check_path } // namespace #endif // BOOST_GRAPH_R_C_SHORTEST_PATHS_HPP