14#ifndef OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_FILTERS_H_
15#define OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_FILTERS_H_
19#include <initializer_list>
24#include "absl/strings/string_view.h"
25#include "absl/types/span.h"
46 int path, int64_t capacity, int64_t span_upper_bound,
47 absl::Span<const DimensionValues::Interval> cumul_of_node,
48 absl::Span<const DimensionValues::Interval> slack_of_node,
49 absl::AnyInvocable<int64_t(int64_t, int64_t)
const> evaluator,
54 absl::AnyInvocable<int64_t(int64_t, int64_t)
const> pre_travel_evaluator,
55 absl::AnyInvocable<int64_t(int64_t, int64_t)
const> post_travel_evaluator,
65 absl::Span<
const std::pair<int64_t, int64_t>> interbreaks);
69 const RoutingModel& routing_model);
73 const RoutingModel& routing_model);
78 const RoutingModel& routing_model);
82 const RoutingModel& routing_model,
bool filter_cost);
86 const RoutingModel& routing_model);
90 const RoutingModel& routing_model);
94 bool propagate_own_objective_value,
95 bool filter_objective_cost,
96 bool may_use_optimizers);
100 const RoutingDimension& dimension);
112 bool propagate_own_objective_value,
bool filter_objective_cost);
181 PathState(
int num_nodes, std::vector<int> path_start,
182 std::vector<int> path_end);
191 int Start(
int path)
const {
return path_start_end_[path].start; }
193 int End(
int path)
const {
return path_start_end_[path].end; }
201 int Path(
int node)
const {
return committed_paths_[node]; }
204 const std::vector<int>&
ChangedPaths()
const {
return changed_paths_; }
206 const std::vector<int>&
ChangedLoops()
const {
return changed_loops_; }
208 ChainRange
Chains(
int path)
const;
210 NodeRange
Nodes(
int path)
const;
219 void ChangePath(
int path, absl::Span<const ChainBounds> chains);
222 void ChangePath(
int path,
const std::initializer_list<ChainBounds>& chains) {
223 changed_paths_.push_back(path);
224 const int path_begin_index = chains_.size();
225 chains_.insert(chains_.end(), chains.begin(), chains.end());
226 const int path_end_index = chains_.size();
227 paths_[path] = {path_begin_index, path_end_index};
229 chains_.emplace_back(0, 0);
251 struct PathStartEnd {
252 PathStartEnd(
int start,
int end) : start(start),
end(
end) {}
264 void CopyNewPathAtEndOfNodes(
int path);
267 void IncrementalCommit();
273 const int num_nodes_;
274 const int num_paths_;
275 std::vector<PathStartEnd> path_start_end_;
303 std::vector<int> committed_nodes_;
305 std::vector<int> committed_paths_;
307 std::vector<int> committed_index_;
308 const int num_nodes_threshold_;
309 std::vector<ChainBounds> chains_;
310 std::vector<PathBounds> paths_;
313 std::vector<int> changed_paths_;
314 std::vector<int> changed_loops_;
317 bool is_invalid_ =
false;
331 return current_node_ != other.current_node_;
337 explicit Iterator(
const int* node) : current_node_(node) {}
338 const int* current_node_;
343 Chain(
const int* begin_node,
const int* end_node)
344 : begin_(begin_node), end_(end_node) {}
347 int First()
const {
return *begin_; }
348 int Last()
const {
return *(end_ - 1); }
355 const int*
const begin_;
356 const int*
const end_;
369 return {first_node_ + current_chain_->begin_index,
370 first_node_ + current_chain_->end_index};
373 return current_chain_ != other.current_chain_;
379 Iterator(
const ChainBounds* chain,
const int*
const first_node)
380 : current_chain_(chain), first_node_(first_node) {}
382 const int*
const first_node_;
388 const ChainBounds*
const end_chain,
const int*
const first_node)
389 : begin_(begin_chain), end_(end_chain), first_node_(first_node) {}
395 return (begin_ == end_) ? *this :
ChainRange(begin_ + 1, end_, first_node_);
399 return (begin_ == end_) ? *this :
ChainRange(begin_, end_ - 1, first_node_);
405 const int*
const first_node_;
416 if (current_node_ == end_node_) {
422 end_node_ = first_node_ + bounds.
end_index;
428 return current_chain_ != other.current_chain_;
434 Iterator(
const ChainBounds* current_chain,
const int*
const first_node)
435 : current_node_(first_node + current_chain->begin_index),
436 end_node_(first_node + current_chain->end_index),
437 current_chain_(current_chain),
438 first_node_(first_node) {}
439 const int* current_node_;
440 const int* end_node_;
442 const int*
const first_node_;
448 const int* first_node)
449 : begin_chain_(begin_chain),
450 end_chain_(end_chain),
451 first_node_(first_node) {}
460 const int*
const first_node_;
469 std::unique_ptr<PathState> path_state,
470 const std::vector<IntVar*>& nexts);
479 const RoutingModel& routing_model,
const PathState* path_state,
480 const std::vector<PickupDeliveryPair>& pairs,
481 const std::vector<RoutingModel::PickupAndDeliveryPolicy>& vehicle_policies);
508 std::vector<Interval> path_capacity,
509 std::vector<int> path_class,
510 std::vector<std::function<
Interval(int64_t, int64_t)>>
511 demand_per_path_class,
512 std::vector<Interval> node_capacity,
526 inline void UpdateCumulUsingChainRIQ(
int first_index,
int last_index,
534 void IncrementalCommit();
537 void AppendPathDemandsToSums(
int path);
543 void UpdateRIQStructure(
int begin_index,
int end_index);
546 const std::vector<ExtendedInterval> path_capacity_;
547 const std::vector<int> path_class_;
548 const std::vector<std::function<
Interval(int64_t, int64_t)>>
549 demand_per_path_class_;
550 std::vector<ExtendedInterval> cached_demand_;
551 const std::vector<ExtendedInterval> node_capacity_;
557 std::vector<int> index_;
579 std::vector<std::vector<RIQNode>> riq_;
582 const int maximum_riq_layer_size_;
584 const int min_range_size_for_riq_;
595 Solver* solver, std::unique_ptr<DimensionChecker> checker,
596 absl::string_view dimension_name);
625 std::vector<PathData> path_data);
633 std::vector<PathData> path_data_;
637 Solver* solver, std::unique_ptr<LightVehicleBreaksChecker> checker,
638 absl::string_view dimension_name);
737 int TreeSize()
const {
return tree_location_.size(); }
741 elements_.push_back({.height = height, .weight = weight});
759 int end_index)
const;
769 std::vector<Element> elements_;
773 struct TreeLocation {
778 std::vector<TreeLocation> tree_location_;
783 int64_t pivot_height;
785 bool operator<(
const Node& other)
const {
786 return pivot_height < other.pivot_height;
788 bool operator==(
const Node& other)
const {
789 return pivot_height == other.pivot_height;
792 std::vector<Node> nodes_;
805 unsigned int is_left : 1;
820 std::vector<std::vector<ElementInfo>> tree_layers_;
825 struct ElementRange {
826 int range_first_index;
827 int range_last_index;
831 bool range_first_is_node_first;
833 bool Empty()
const {
return range_first_index > range_last_index; }
835 int64_t Sum(
const ElementInfo* elements)
const {
836 return elements[range_last_index].prefix_sum -
837 (range_first_is_node_first
839 : elements[range_first_index - 1].prefix_sum);
842 ElementRange RightSubRange(
const ElementInfo* els,
int pivot_index)
const {
846 (range_first_index - els[range_first_index].left_index),
849 (range_last_index - els[range_last_index].left_index) -
850 static_cast<int>(els[range_last_index].is_left),
851 .range_first_is_node_first =
false};
852 right.range_first_is_node_first = right.range_first_index == pivot_index;
856 ElementRange LeftSubRange(
const ElementInfo* els)
const {
857 return {.range_first_index = els[range_first_index].left_index,
858 .range_last_index = els[range_last_index].left_index -
859 !els[range_last_index].is_left,
860 .range_first_is_node_first = range_first_is_node_first};
881 const PathState* path_state, std::vector<int64_t> force_start_min,
882 std::vector<int64_t> force_end_min, std::vector<int> force_class,
883 std::vector<
const std::function<int64_t(int64_t)>*> force_per_class,
884 std::vector<int> distance_class,
885 std::vector<
const std::function<int64_t(int64_t, int64_t)>*>
887 std::vector<EnergyCost> path_energy_cost,
888 std::vector<bool> path_has_cost_when_empty);
895 int64_t ComputePathCost(int64_t path)
const;
896 void CacheAndPrecomputeRangeQueriesOfPath(
int path);
897 void IncrementalCacheAndPrecompute();
898 void FullCacheAndPrecompute();
901 const std::vector<int64_t> force_start_min_;
902 const std::vector<int64_t> force_end_min_;
903 const std::vector<int> force_class_;
904 const std::vector<int> distance_class_;
905 const std::vector<
const std::function<int64_t(int64_t)>*> force_per_class_;
906 const std::vector<
const std::function<int64_t(int64_t, int64_t)>*>
908 const std::vector<EnergyCost> path_energy_cost_;
909 const std::vector<bool> path_has_cost_when_empty_;
912 const int maximum_range_query_size_;
916 std::vector<int> force_rmq_index_of_node_;
924 std::vector<int> threshold_query_index_of_node_;
926 std::vector<int64_t> cached_force_;
927 std::vector<int64_t> cached_distance_;
930 int64_t committed_total_cost_;
931 int64_t accepted_total_cost_;
932 std::vector<int64_t> committed_path_cost_;
936 Solver* solver, std::unique_ptr<PathEnergyCostChecker> checker,
937 absl::string_view dimension_name);
942 const PathState* path_state,
943 const std::vector<RoutingDimension*>& dimensions,
944 std::vector<LocalSearchFilterManager::FilterEvent>* filters);
947 const std::vector<RoutingDimension*>& dimensions,
948 const RoutingSearchParameters& parameters,
bool filter_objective_cost,
949 bool use_chain_cumul_filter,
950 std::vector<LocalSearchFilterManager::FilterEvent>* filters);
956 BasePathFilter(
const std::vector<IntVar*>& nexts,
int next_domain_size,
957 const PathsMetadata& paths_metadata);
960 int64_t objective_min, int64_t objective_max)
override;
972 for (int64_t start : paths_metadata_.Starts()) {
977 int NumPaths()
const {
return paths_metadata_.NumPaths(); }
978 int64_t
Start(
int i)
const {
return paths_metadata_.Start(i); }
979 int64_t
End(
int i)
const {
return paths_metadata_.End(i); }
980 int GetPath(int64_t node)
const {
return paths_metadata_.GetPath(node); }
981 int Rank(int64_t node)
const {
return ranks_[node]; }
983 return touched_paths_.PositionsSetAtLeastOnce();
987 return new_synchronized_unperformed_nodes_.PositionsSetAtLeastOnce();
993 virtual void OnBeforeSynchronizePaths(
bool) {}
994 virtual void OnAfterSynchronizePaths() {}
995 virtual void OnSynchronizePathFromStart(int64_t) {}
996 virtual bool InitializeAcceptPath() {
return true; }
997 virtual bool AcceptPath(int64_t path_start, int64_t chain_start,
998 int64_t chain_end) = 0;
999 virtual bool FinalizeAcceptPath(int64_t, int64_t) {
return true; }
1001 void ComputePathStarts(std::vector<int64_t>* path_starts,
1002 std::vector<int>* index_to_path);
1003 bool HavePathsChanged();
1004 void SynchronizeFullAssignment();
1005 void UpdateAllRanks();
1006 void UpdatePathRanksFromStart(
int start);
1008 const PathsMetadata& paths_metadata_;
1009 std::vector<int64_t> node_path_starts_;
1010 SparseBitset<int64_t> new_synchronized_unperformed_nodes_;
1011 std::vector<int64_t> new_nexts_;
1012 std::vector<int> delta_touched_;
1013 SparseBitset<> touched_paths_;
1015 std::vector<std::pair<int64_t, int64_t> > touched_path_chain_start_ends_;
1017 std::vector<int> ranks_;
~BasePathFilter() override=default
static const int64_t kUnassigned
bool lns_detected() const
bool PathStartTouched(int64_t start) const
BasePathFilter(const std::vector< IntVar * > &nexts, int next_domain_size, const PathsMetadata &paths_metadata)
int64_t GetNext(int64_t node) const
const std::vector< int64_t > & GetTouchedPathStarts() const
bool Accept(const Assignment *delta, const Assignment *deltadelta, int64_t objective_min, int64_t objective_max) override
bool HasAnySyncedPath() const
int GetPath(int64_t node) const
int Rank(int64_t node) const
const std::vector< int64_t > & GetNewSynchronizedUnperformedNodes() const
void OnSynchronize(const Assignment *delta) override
int64_t Start(int i) const
DimensionChecker(const PathState *path_state, std::vector< Interval > path_capacity, std::vector< int > path_class, std::vector< std::function< Interval(int64_t, int64_t)> > demand_per_path_class, std::vector< Interval > node_capacity, int min_range_size_for_riq=kOptimalMinRangeSizeForRIQ)
static constexpr int kOptimalMinRangeSizeForRIQ
IntVarLocalSearchFilter(const std::vector< IntVar * > &vars)
int64_t Value(int index) const
bool IsVarSynced(int index) const
LightVehicleBreaksChecker(PathState *path_state, std::vector< PathData > path_data)
PathEnergyCostChecker(const PathState *path_state, std::vector< int64_t > force_start_min, std::vector< int64_t > force_end_min, std::vector< int > force_class, std::vector< const std::function< int64_t(int64_t)> * > force_per_class, std::vector< int > distance_class, std::vector< const std::function< int64_t(int64_t, int64_t)> * > distance_per_class, std::vector< EnergyCost > path_energy_cost, std::vector< bool > path_has_cost_when_empty)
int64_t AcceptedCost() const
int64_t CommittedCost() const
bool operator!=(Iterator other) const
friend class ChainRange
Only a ChainRange can construct its Iterator.
A ChainRange is a range of Chains, committed or not.
ChainRange DropLastChain() const
ChainRange DropFirstChain() const
ChainRange(const ChainBounds *const begin_chain, const ChainBounds *const end_chain, const int *const first_node)
bool operator!=(Iterator other) const
A Chain is a range of committed nodes.
Chain(const int *begin_node, const int *end_node)
Chain WithoutFirstNode() const
bool operator!=(Iterator other) const
friend class NodeRange
Only a NodeRange can construct its Iterator.
NodeRange(const ChainBounds *begin_chain, const ChainBounds *end_chain, const int *first_node)
int NumNodes() const
Instance-constant accessors.
void ChangeLoops(absl::Span< const int > new_loops)
Describes the nodes that are newly loops in this change.
const std::vector< int > & ChangedLoops() const
Returns the set of loops that were added by the change.
void Reset()
Sets all paths to start->end, all other nodes to kUnassigned.
const std::vector< int > & ChangedPaths() const
void Commit()
Set the current state G1 as committed. See class comment for details.
ChainBounds CommittedPathRange(int path) const
ChainRange Chains(int path) const
Returns the current range of chains of path.
static constexpr int kUnassigned
State-dependent accessors.
int NumPaths() const
Returns the number of paths (empty paths included).
void Revert()
Erase incremental changes. See class comment for details.
NodeRange Nodes(int path) const
Returns the current range of nodes of path.
int End(int path) const
Returns the end of a path.
PathState(int num_nodes, std::vector< int > path_start, std::vector< int > path_end)
static constexpr int kLoop
void ChangePath(int path, const std::initializer_list< ChainBounds > &chains)
int CommittedIndex(int node) const
void ChangePath(int path, absl::Span< const ChainBounds > chains)
State modifiers.
int Start(int path) const
Returns the start of a path.
For the time being, Solver is neither MT_SAFE nor MT_HOT.
void MakeTreeFromNewElements()
WeightedWaveletTree()=default
void PushBack(int64_t height, int64_t weight)
Adds an element at index this->Size().
int64_t RangeSumWithThreshold(int64_t threshold_height, int begin_index, int end_index) const
int TreeSize() const
Returns the total number of elements in trees.
In SWIG mode, we don't want anything besides these top-level includes.
IntVarLocalSearchFilter * MakeVehicleAmortizedCostFilter(const RoutingModel &routing_model)
Returns a filter computing vehicle amortized costs.
bool FillDimensionValuesFromRoutingDimension(int path, int64_t capacity, int64_t span_upper_bound, absl::Span< const DimensionValues::Interval > cumul_of_node, absl::Span< const DimensionValues::Interval > slack_of_node, absl::AnyInvocable< int64_t(int64_t, int64_t) const > evaluator, DimensionValues &dimension_values)
IntVarLocalSearchFilter * MakeRouteConstraintFilter(const RoutingModel &routing_model)
Returns a filter tracking route constraints.
LocalSearchFilter * MakePickupDeliveryFilter(const RoutingModel &routing_model, const PathState *path_state, const std::vector< PickupDeliveryPair > &pairs, const std::vector< RoutingModel::PickupAndDeliveryPolicy > &vehicle_policies)
IntVarLocalSearchFilter * MakeMaxActiveVehiclesFilter(const RoutingModel &routing_model)
Returns a filter ensuring that max active vehicles constraints are enforced.
void AppendLightWeightDimensionFilters(const PathState *path_state, const std::vector< RoutingDimension * > &dimensions, std::vector< LocalSearchFilterManager::FilterEvent > *filters)
IntVarLocalSearchFilter * MakeNodeDisjunctionFilter(const RoutingModel &routing_model, bool filter_cost)
Returns a filter ensuring that node disjunction constraints are enforced.
LocalSearchFilter * MakePathEnergyCostFilter(Solver *solver, std::unique_ptr< PathEnergyCostChecker > checker, absl::string_view dimension_name)
void FillPrePostVisitValues(int path, const DimensionValues &dimension_values, absl::AnyInvocable< int64_t(int64_t, int64_t) const > pre_travel_evaluator, absl::AnyInvocable< int64_t(int64_t, int64_t) const > post_travel_evaluator, PrePostVisitValues &visit_values)
IntVarLocalSearchFilter * MakeCumulBoundsPropagatorFilter(const RoutingDimension &dimension)
Returns a filter handling dimension cumul bounds.
LocalSearchFilter * MakePathStateFilter(Solver *solver, std::unique_ptr< PathState > path_state, const std::vector< IntVar * > &nexts)
ClosedInterval::Iterator end(ClosedInterval interval)
LocalSearchFilter * MakeLightVehicleBreaksFilter(Solver *solver, std::unique_ptr< LightVehicleBreaksChecker > checker, absl::string_view dimension_name)
IntVarLocalSearchFilter * MakePathCumulFilter(const RoutingDimension &dimension, bool propagate_own_objective_value, bool filter_objective_cost, bool may_use_optimizers)
Returns a filter handling dimension costs and constraints.
IntVarLocalSearchFilter * MakeCPFeasibilityFilter(RoutingModel *routing_model)
Returns a filter checking the current solution using CP propagation.
LocalSearchFilter * MakeVehicleVarFilter(const RoutingModel &routing_model, const PathState *path_state)
Returns a filter checking that vehicle variable domains are respected.
void AppendDimensionCumulFilters(const std::vector< RoutingDimension * > &dimensions, const RoutingSearchParameters ¶meters, bool filter_objective_cost, bool use_chain_cumul_filter, std::vector< LocalSearchFilterManager::FilterEvent > *filters)
LocalSearchFilter * MakeResourceAssignmentFilter(LocalDimensionCumulOptimizer *lp_optimizer, LocalDimensionCumulOptimizer *mp_optimizer, bool propagate_own_objective_value, bool filter_objective_cost)
bool PropagateLightweightVehicleBreaks(int path, DimensionValues &dimension_values, absl::Span< const std::pair< int64_t, int64_t > > interbreaks)
IntVarLocalSearchFilter * MakeTypeRegulationsFilter(const RoutingModel &routing_model)
Returns a filter ensuring type regulation constraints are enforced.
IntVarLocalSearchFilter * MakeGlobalLPCumulFilter(GlobalDimensionCumulOptimizer *lp_optimizer, GlobalDimensionCumulOptimizer *mp_optimizer, bool filter_objective_cost)
Returns a filter checking global linear constraints and costs.
util_intops::StrongIntRange< ElementIndex > ElementRange
IntVarLocalSearchFilter * MakeActiveNodeGroupFilter(const RoutingModel &routing_model)
LocalSearchFilter * MakeDimensionFilter(Solver *solver, std::unique_ptr< DimensionChecker > checker, absl::string_view dimension_name)
int64_t num_positive_infinity
int64_t num_negative_infinity
int64_t max_interbreak_duration
int64_t min_break_duration
std::vector< VehicleBreak > vehicle_breaks
LocalSearchState::Variable start_cumul
LocalSearchState::Variable end_cumul
std::vector< InterbreakLimit > interbreak_limits
LocalSearchState::Variable total_transit
LocalSearchState::Variable span
int64_t cost_per_unit_above_threshold
int64_t cost_per_unit_below_threshold
ChainBounds(int begin_index, int end_index)
static const int64_t kint64max