From 36a29b2ddfd8660c3617452a3d1dd59b415e1258 Mon Sep 17 00:00:00 2001 From: Mizux Seiha Date: Thu, 20 Oct 2022 18:06:52 +0200 Subject: [PATCH] routing(swig): Expose SimpleBoundCost related methods (Fix #1815) * Extract BoundCost from SimpleBoundCost since SWIG do not support nested class * Wrap it in all languages * Expose new API * SoftSpanUpperBoundForVehicle * QuadraticCostSoftSpanUpperBoundForVehicle * Add tests --- .../csharp/RoutingSolverTests.cs | 115 ++++++++++++++++++ ortools/constraint_solver/csharp/routing.i | 6 + .../java/RoutingSolverTest.java | 88 +++++++++++++- ortools/constraint_solver/java/routing.i | 16 +++ .../python/pywraprouting_test.py | 73 +++++++++++ ortools/constraint_solver/python/routing.i | 8 ++ ortools/constraint_solver/routing.cc | 4 +- ortools/constraint_solver/routing.h | 29 ++--- ortools/constraint_solver/routing_filters.cc | 8 +- .../routing_lp_scheduling.cc | 2 +- 10 files changed, 326 insertions(+), 23 deletions(-) diff --git a/ortools/constraint_solver/csharp/RoutingSolverTests.cs b/ortools/constraint_solver/csharp/RoutingSolverTests.cs index 20621f4c90..a5b604f8e4 100644 --- a/ortools/constraint_solver/csharp/RoutingSolverTests.cs +++ b/ortools/constraint_solver/csharp/RoutingSolverTests.cs @@ -12,6 +12,7 @@ // limitations under the License. using System; +using System.Linq; using Xunit; using Google.OrTools.ConstraintSolver; @@ -213,4 +214,118 @@ public class RoutingSolverTest Assert.Equal(5, solution.ObjectiveValue()); } } + +public class BoundCostTest +{ + [Fact] + public void TestCtor() + { + // Create Routing Index Manager + BoundCost boundCost = new BoundCost(); + Assert.NotNull(boundCost); + Assert.Equal(0, boundCost.bound); + Assert.Equal(0, boundCost.cost); + + boundCost = new BoundCost(97 /*bound*/, 101 /*cost*/); + Assert.NotNull(boundCost); + Assert.Equal(97, boundCost.bound); + Assert.Equal(101, boundCost.cost); + } +} + +public class RoutingDimensionTest +{ + [Fact] + public void TestCtor() + { + // Create Routing Index Manager + RoutingIndexManager manager = new RoutingIndexManager(31 /*locations*/, 7 /*vehicle*/, 3 /*depot*/); + Assert.NotNull(manager); + // Create Routing Model. + RoutingModel routing = new RoutingModel(manager); + Assert.NotNull(routing); + // Create a distance callback. + int transitIndex = routing.RegisterTransitCallback((long fromIndex, long toIndex) => + { + // Convert from routing variable Index to + // distance matrix NodeIndex. + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return Math.Abs(toNode - fromNode); + }); + Assert.True(routing.AddDimension(transitIndex, 100, 100, true, "Dimension")); + RoutingDimension dimension = routing.GetDimensionOrDie("Dimension"); + } + + [Fact] + public void TestSoftSpanUpperBound() + { + // Create Routing Index Manager + RoutingIndexManager manager = new RoutingIndexManager(31 /*locations*/, 7 /*vehicle*/, 3 /*depot*/); + Assert.NotNull(manager); + // Create Routing Model. + RoutingModel routing = new RoutingModel(manager); + Assert.NotNull(routing); + // Create a distance callback. + int transitIndex = routing.RegisterTransitCallback((long fromIndex, long toIndex) => + { + // Convert from routing variable Index to + // distance matrix NodeIndex. + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return Math.Abs(toNode - fromNode); + }); + Assert.True(routing.AddDimension(transitIndex, 100, 100, true, "Dimension")); + RoutingDimension dimension = routing.GetDimensionOrDie("Dimension"); + + BoundCost boundCost = new BoundCost(/*bound=*/97, /*cost=*/43); + Assert.NotNull(boundCost); + Assert.False(dimension.HasSoftSpanUpperBounds()); + foreach (int v in Enumerable.Range(0, manager.GetNumberOfVehicles()).ToArray()) + { + dimension.SetSoftSpanUpperBoundForVehicle(boundCost, v); + BoundCost bc = dimension.GetSoftSpanUpperBoundForVehicle(v); + Assert.NotNull(bc); + Assert.Equal(97, bc.bound); + Assert.Equal(43, bc.cost); + } + Assert.True(dimension.HasSoftSpanUpperBounds()); + } + + [Fact] + public void TestQuadraticCostSoftSpanUpperBound() + { + // Create Routing Index Manager + RoutingIndexManager manager = new RoutingIndexManager(31 /*locations*/, 7 /*vehicle*/, 3 /*depot*/); + Assert.NotNull(manager); + // Create Routing Model. + RoutingModel routing = new RoutingModel(manager); + Assert.NotNull(routing); + // Create a distance callback. + int transitIndex = routing.RegisterTransitCallback((long fromIndex, long toIndex) => + { + // Convert from routing variable Index to + // distance matrix NodeIndex. + var fromNode = manager.IndexToNode(fromIndex); + var toNode = manager.IndexToNode(toIndex); + return Math.Abs(toNode - fromNode); + }); + Assert.True(routing.AddDimension(transitIndex, 100, 100, true, "Dimension")); + RoutingDimension dimension = routing.GetDimensionOrDie("Dimension"); + + BoundCost boundCost = new BoundCost(/*bound=*/97, /*cost=*/43); + Assert.NotNull(boundCost); + Assert.False(dimension.HasQuadraticCostSoftSpanUpperBounds()); + foreach (int v in Enumerable.Range(0, manager.GetNumberOfVehicles()).ToArray()) + { + dimension.SetQuadraticCostSoftSpanUpperBoundForVehicle(boundCost, v); + BoundCost bc = dimension.GetQuadraticCostSoftSpanUpperBoundForVehicle(v); + Assert.NotNull(bc); + Assert.Equal(97, bc.bound); + Assert.Equal(43, bc.cost); + } + Assert.True(dimension.HasQuadraticCostSoftSpanUpperBounds()); + } +} + } // namespace Google.OrTools.Tests diff --git a/ortools/constraint_solver/csharp/routing.i b/ortools/constraint_solver/csharp/routing.i index 693f34d160..e9de3eb07e 100644 --- a/ortools/constraint_solver/csharp/routing.i +++ b/ortools/constraint_solver/csharp/routing.i @@ -167,6 +167,12 @@ using System.Collections.Generic; %unignore TypeRegulationsChecker; %ignore TypeRegulationsChecker::CheckVehicle; +// SimpleBoundCosts +%unignore BoundCost; +%unignore SimpleBoundCosts; +%rename("GetBoundCost") SimpleBoundCosts::bound_cost; +%rename("GetSize") SimpleBoundCosts::Size; + } // namespace operations_research %rename("GetStatus") operations_research::RoutingModel::status; diff --git a/ortools/constraint_solver/java/RoutingSolverTest.java b/ortools/constraint_solver/java/RoutingSolverTest.java index 71ebd277b4..b0eaa5d4df 100644 --- a/ortools/constraint_solver/java/RoutingSolverTest.java +++ b/ortools/constraint_solver/java/RoutingSolverTest.java @@ -15,17 +15,17 @@ package com.google.ortools.constraintsolver; import static com.google.common.truth.Truth.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.auto.value.AutoValue; import com.google.ortools.Loader; -import com.google.ortools.constraintsolver.RoutingModelParameters; -import com.google.ortools.constraintsolver.RoutingSearchParameters; import com.google.protobuf.Duration; import java.util.ArrayList; import java.util.function.LongBinaryOperator; import java.util.function.LongUnaryOperator; +import java.util.stream.IntStream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -690,4 +690,88 @@ public final class RoutingSolverTest { IntVar[] vehicleVars = model.vehicleVars(); assertThat(vehicleVars).isNotEmpty(); } + + @Test + public void testBoundCost_Ctor() { + // Create Routing Index Manager + BoundCost boundCost = new BoundCost(); + assertNotNull(boundCost); + assertEquals(0, boundCost.getBound()); + assertEquals(0, boundCost.getCost()); + + boundCost = new BoundCost(97 /*bound*/, 101 /*cost*/); + assertNotNull(boundCost); + assertEquals(97, boundCost.getBound()); + assertEquals(101, boundCost.getCost()); + } + + @Test + public void testRoutingDimension_Ctor() { + final RoutingIndexManager manager = new RoutingIndexManager(31, 7, 3); + assertNotNull(manager); + final RoutingModel model = new RoutingModel(manager); + assertNotNull(model); + final int transitIndex = model.registerTransitCallback((long fromIndex, long toIndex) -> { + final int fromNode = manager.indexToNode(fromIndex); + final int toNode = manager.indexToNode(toIndex); + return (long) Math.abs(toNode - fromNode); + }); + assertTrue(model.addDimension(transitIndex, 100, 100, true, "Dimension")); + final RoutingDimension dimension = model.getMutableDimension("Dimension"); + } + + @Test + public void testRoutingDimension_SoftSpanUpperBound() { + final RoutingIndexManager manager = new RoutingIndexManager(31, 7, 3); + assertNotNull(manager); + final RoutingModel model = new RoutingModel(manager); + assertNotNull(model); + final int transitIndex = model.registerTransitCallback((long fromIndex, long toIndex) -> { + final int fromNode = manager.indexToNode(fromIndex); + final int toNode = manager.indexToNode(toIndex); + return (long) Math.abs(toNode - fromNode); + }); + assertTrue(model.addDimension(transitIndex, 100, 100, true, "Dimension")); + final RoutingDimension dimension = model.getMutableDimension("Dimension"); + + final BoundCost boundCost = new BoundCost(97 /*bound*/, 101 /*cost*/); + assertNotNull(boundCost); + assertFalse(dimension.hasSoftSpanUpperBounds()); + for (int v : IntStream.range(0, manager.getNumberOfVehicles()).toArray()) { + dimension.setSoftSpanUpperBoundForVehicle(boundCost, v); + final BoundCost bc = dimension.getSoftSpanUpperBoundForVehicle(v); + assertNotNull(bc); + assertEquals(97, bc.getBound()); + assertEquals(101, bc.getCost()); + } + assertTrue(dimension.hasSoftSpanUpperBounds()); + } + + @Test + public void testRoutingDimension_QuadraticCostSoftSpanUpperBound() { + final RoutingIndexManager manager = new RoutingIndexManager(31, 7, 3); + assertNotNull(manager); + final RoutingModel model = new RoutingModel(manager); + assertNotNull(model); + final int transitIndex = model.registerTransitCallback((long fromIndex, long toIndex) -> { + final int fromNode = manager.indexToNode(fromIndex); + final int toNode = manager.indexToNode(toIndex); + return (long) Math.abs(toNode - fromNode); + }); + assertTrue(model.addDimension(transitIndex, 100, 100, true, "Dimension")); + final RoutingDimension dimension = model.getMutableDimension("Dimension"); + + final BoundCost boundCost = new BoundCost(97 /*bound*/, 101 /*cost*/); + assertNotNull(boundCost); + assertFalse(dimension.hasQuadraticCostSoftSpanUpperBounds()); + for (int v : IntStream.range(0, manager.getNumberOfVehicles()).toArray()) { + dimension.setQuadraticCostSoftSpanUpperBoundForVehicle(boundCost, v); + final BoundCost bc = dimension.getQuadraticCostSoftSpanUpperBoundForVehicle(v); + assertNotNull(bc); + assertEquals(97, bc.getBound()); + assertEquals(101, bc.getCost()); + } + assertTrue(dimension.hasQuadraticCostSoftSpanUpperBounds()); + + } } diff --git a/ortools/constraint_solver/java/routing.i b/ortools/constraint_solver/java/routing.i index 2b674151d1..e88887b2d6 100644 --- a/ortools/constraint_solver/java/routing.i +++ b/ortools/constraint_solver/java/routing.i @@ -251,6 +251,16 @@ import java.util.function.LongBinaryOperator; %rename (getCumulVarSoftUpperBound) RoutingDimension::GetCumulVarSoftUpperBound; %rename (getCumulVarSoftUpperBoundCoefficient) RoutingDimension::GetCumulVarSoftUpperBoundCoefficient; %rename (getGlobalSpanCostCoefficient) RoutingDimension::global_span_cost_coefficient; +%rename (getLocalOptimizerOffsetForVehicle) RoutingDimension::GetLocalOptimizerOffsetForVehicle; + +%rename (setSoftSpanUpperBoundForVehicle) RoutingDimension::SetSoftSpanUpperBoundForVehicle; +%rename (hasSoftSpanUpperBounds) RoutingDimension::HasSoftSpanUpperBounds; +%rename (getSoftSpanUpperBoundForVehicle) RoutingDimension::GetSoftSpanUpperBoundForVehicle; + +%rename (setQuadraticCostSoftSpanUpperBoundForVehicle) RoutingDimension::SetQuadraticCostSoftSpanUpperBoundForVehicle; +%rename (hasQuadraticCostSoftSpanUpperBounds) RoutingDimension::HasQuadraticCostSoftSpanUpperBounds; +%rename (getQuadraticCostSoftSpanUpperBoundForVehicle) RoutingDimension::GetQuadraticCostSoftSpanUpperBoundForVehicle; + %rename (getGroupDelay) RoutingDimension::GetGroupDelay; %rename (getNodeVisitTransitsOfVehicle) RoutingDimension::GetNodeVisitTransitsOfVehicle; %rename (getSpanCostCoefficientForVehicle) RoutingDimension::GetSpanCostCoefficientForVehicle; @@ -286,6 +296,12 @@ import java.util.function.LongBinaryOperator; %unignore TypeRegulationsChecker; %ignore TypeRegulationsChecker::CheckVehicle; +// SimpleBoundCosts +%unignore BoundCost; +%unignore SimpleBoundCosts; +%rename (getBoundCost) SimpleBoundCosts::bound_cost; +%rename (getSize) SimpleBoundCosts::Size; + } // namespace operations_research // Generic rename rules. diff --git a/ortools/constraint_solver/python/pywraprouting_test.py b/ortools/constraint_solver/python/pywraprouting_test.py index c5779fcb56..574f4c7eff 100755 --- a/ortools/constraint_solver/python/pywraprouting_test.py +++ b/ortools/constraint_solver/python/pywraprouting_test.py @@ -722,5 +722,78 @@ class TestRoutingModel(unittest.TestCase): count += 1 +class TestBoundCost(unittest.TestCase): + + def testCtor(self): + bound_cost = pywrapcp.BoundCost() + self.assertIsNotNone(bound_cost) + self.assertEqual(0, bound_cost.bound) + self.assertEqual(0, bound_cost.cost) + + bound_cost = pywrapcp.BoundCost(bound=97, cost=43) + self.assertIsNotNone(bound_cost) + self.assertEqual(97, bound_cost.bound) + self.assertEqual(43, bound_cost.cost) + + +class TestRoutingDimension(unittest.TestCase): + + def testCtor(self): + manager = pywrapcp.RoutingIndexManager(31, 7, 3) + self.assertIsNotNone(manager) + model = pywrapcp.RoutingModel(manager) + self.assertIsNotNone(model) + transit_idx = model.RegisterTransitCallback( + partial(TransitDistance, manager)) + self.assertTrue( + model.AddDimension(transit_idx, 90, 90, True, 'distance')) + model.GetDimensionOrDie('distance') + + def testSoftSpanUpperBound(self): + manager = pywrapcp.RoutingIndexManager(31, 7, 3) + self.assertIsNotNone(manager) + model = pywrapcp.RoutingModel(manager) + self.assertIsNotNone(model) + transit_idx = model.RegisterTransitCallback( + partial(TransitDistance, manager)) + self.assertTrue( + model.AddDimension(transit_idx, 100, 100, True, 'distance')) + dimension = model.GetDimensionOrDie('distance') + + bound_cost = pywrapcp.BoundCost(bound=97, cost=43) + self.assertIsNotNone(bound_cost) + self.assertFalse(dimension.HasSoftSpanUpperBounds()) + for v in range(manager.GetNumberOfVehicles()): + dimension.SetSoftSpanUpperBoundForVehicle(bound_cost, v) + bc = dimension.GetSoftSpanUpperBoundForVehicle(v) + self.assertIsNotNone(bc) + self.assertEqual(97, bc.bound) + self.assertEqual(43, bc.cost) + self.assertTrue(dimension.HasSoftSpanUpperBounds()) + + def testQuadraticCostSoftSpanUpperBound(self): + manager = pywrapcp.RoutingIndexManager(31, 7, 3) + self.assertIsNotNone(manager) + model = pywrapcp.RoutingModel(manager) + self.assertIsNotNone(model) + transit_idx = model.RegisterTransitCallback( + partial(TransitDistance, manager)) + self.assertTrue( + model.AddDimension(transit_idx, 100, 100, True, 'distance')) + dimension = model.GetDimensionOrDie('distance') + + bound_cost = pywrapcp.BoundCost(bound=97, cost=43) + self.assertIsNotNone(bound_cost) + self.assertFalse(dimension.HasQuadraticCostSoftSpanUpperBounds()) + for v in range(manager.GetNumberOfVehicles()): + dimension.SetQuadraticCostSoftSpanUpperBoundForVehicle( + bound_cost, v) + bc = dimension.GetQuadraticCostSoftSpanUpperBoundForVehicle(v) + self.assertIsNotNone(bc) + self.assertEqual(97, bc.bound) + self.assertEqual(43, bc.cost) + self.assertTrue(dimension.HasQuadraticCostSoftSpanUpperBounds()) + + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/ortools/constraint_solver/python/routing.i b/ortools/constraint_solver/python/routing.i index cbd9d84aea..89b3e77d3f 100644 --- a/ortools/constraint_solver/python/routing.i +++ b/ortools/constraint_solver/python/routing.i @@ -88,6 +88,14 @@ enum OptionalBoolean { BOOL_FALSE = 2, BOOL_TRUE = 3, }; + +// SimpleBoundCosts +%unignore BoundCost; + +%unignore SimpleBoundCosts; +%unignore SimpleBoundCosts::bound_cost; +%rename("size") SimpleBoundCosts::Size; + } // namespace operations_research // TODO(user): Use ignoreall/unignoreall for this one. A lot of work. diff --git a/ortools/constraint_solver/routing.cc b/ortools/constraint_solver/routing.cc index c20754853b..030a8f28cb 100644 --- a/ortools/constraint_solver/routing.cc +++ b/ortools/constraint_solver/routing.cc @@ -2810,7 +2810,7 @@ void RoutingModel::CloseModelWithParameters( if (dimension->HasSoftSpanUpperBounds()) { for (int vehicle = 0; vehicle < vehicles(); ++vehicle) { if (spans[vehicle]) continue; - const SimpleBoundCosts::BoundCost bound_cost = + const BoundCost bound_cost = dimension->GetSoftSpanUpperBoundForVehicle(vehicle); if (bound_cost.cost == 0) continue; spans[vehicle] = solver_->MakeIntVar(0, span_ubs[vehicle]); @@ -2819,7 +2819,7 @@ void RoutingModel::CloseModelWithParameters( if (dimension->HasQuadraticCostSoftSpanUpperBounds()) { for (int vehicle = 0; vehicle < vehicles(); ++vehicle) { if (spans[vehicle]) continue; - const SimpleBoundCosts::BoundCost bound_cost = + const BoundCost bound_cost = dimension->GetQuadraticCostSoftSpanUpperBoundForVehicle(vehicle); if (bound_cost.cost == 0) continue; spans[vehicle] = solver_->MakeIntVar(0, span_ubs[vehicle]); diff --git a/ortools/constraint_solver/routing.h b/ortools/constraint_solver/routing.h index 281bea9b92..d83bf15a10 100644 --- a/ortools/constraint_solver/routing.h +++ b/ortools/constraint_solver/routing.h @@ -2655,7 +2655,7 @@ class TypeRegulationsConstraint : public Constraint { TypeRequirementChecker requirement_checker_; std::vector vehicle_demons_; }; -#if !defined SWIG + /// A structure meant to store soft bounds and associated violation constants. /// It is 'Simple' because it has one BoundCost per element, /// in contrast to 'Multiple'. Design notes: @@ -2668,12 +2668,15 @@ class TypeRegulationsConstraint : public Constraint { /// because the structure will be accessed through pointers, moreover having /// to type bound_cost reminds the user of the order if they do a copy /// assignment of the element. + +// Can't be nested in SimpleBoundCosts since SWIG doesn't support nested class... +struct BoundCost { + int64_t bound; + int64_t cost; + BoundCost(int64_t bound = 0, int64_t cost = 0): bound(bound), cost(cost) {} +}; class SimpleBoundCosts { public: - struct BoundCost { - int64_t bound; - int64_t cost; - }; SimpleBoundCosts(int num_bounds, BoundCost default_bound_cost) : bound_costs_(num_bounds, default_bound_cost) {} BoundCost& bound_cost(int element) { return bound_costs_[element]; } @@ -2685,7 +2688,6 @@ class SimpleBoundCosts { private: std::vector bound_costs_; }; -#endif // !defined SWIG /// Dimensions represent quantities accumulated at nodes along the routes. They /// represent quantities such as weights or volumes carried along the route, or @@ -3057,21 +3059,21 @@ class RoutingDimension { DCHECK_GE(local_optimizer_offset_for_vehicle_[vehicle], 0); return local_optimizer_offset_for_vehicle_[vehicle]; } -#if !defined SWIG + /// If the span of vehicle on this dimension is larger than bound, /// the cost will be increased by cost * (span - bound). - void SetSoftSpanUpperBoundForVehicle(SimpleBoundCosts::BoundCost bound_cost, + void SetSoftSpanUpperBoundForVehicle(BoundCost bound_cost, int vehicle) { if (!HasSoftSpanUpperBounds()) { vehicle_soft_span_upper_bound_ = std::make_unique( - model_->vehicles(), SimpleBoundCosts::BoundCost{kint64max, 0}); + model_->vehicles(), BoundCost{kint64max, 0}); } vehicle_soft_span_upper_bound_->bound_cost(vehicle) = bound_cost; } bool HasSoftSpanUpperBounds() const { return vehicle_soft_span_upper_bound_ != nullptr; } - SimpleBoundCosts::BoundCost GetSoftSpanUpperBoundForVehicle( + BoundCost GetSoftSpanUpperBoundForVehicle( int vehicle) const { DCHECK(HasSoftSpanUpperBounds()); return vehicle_soft_span_upper_bound_->bound_cost(vehicle); @@ -3079,11 +3081,11 @@ class RoutingDimension { /// If the span of vehicle on this dimension is larger than bound, /// the cost will be increased by cost * (span - bound)^2. void SetQuadraticCostSoftSpanUpperBoundForVehicle( - SimpleBoundCosts::BoundCost bound_cost, int vehicle) { + BoundCost bound_cost, int vehicle) { if (!HasQuadraticCostSoftSpanUpperBounds()) { vehicle_quadratic_cost_soft_span_upper_bound_ = std::make_unique( - model_->vehicles(), SimpleBoundCosts::BoundCost{kint64max, 0}); + model_->vehicles(), BoundCost{kint64max, 0}); } vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle) = bound_cost; @@ -3091,12 +3093,11 @@ class RoutingDimension { bool HasQuadraticCostSoftSpanUpperBounds() const { return vehicle_quadratic_cost_soft_span_upper_bound_ != nullptr; } - SimpleBoundCosts::BoundCost GetQuadraticCostSoftSpanUpperBoundForVehicle( + BoundCost GetQuadraticCostSoftSpanUpperBoundForVehicle( int vehicle) const { DCHECK(HasQuadraticCostSoftSpanUpperBounds()); return vehicle_quadratic_cost_soft_span_upper_bound_->bound_cost(vehicle); } -#endif /// !defined SWIG private: struct SoftBound { diff --git a/ortools/constraint_solver/routing_filters.cc b/ortools/constraint_solver/routing_filters.cc index cf3bc4049f..c04da10e34 100644 --- a/ortools/constraint_solver/routing_filters.cc +++ b/ortools/constraint_solver/routing_filters.cc @@ -1473,7 +1473,7 @@ void PathCumulFilter::OnBeforeSynchronizePaths() { CapSub(span_lower_bound, total_transit))); } if (FilterSoftSpanCost()) { - const SimpleBoundCosts::BoundCost bound_cost = + const BoundCost bound_cost = dimension_.GetSoftSpanUpperBoundForVehicle(vehicle); if (bound_cost.bound < span_lower_bound) { const int64_t violation = @@ -1483,7 +1483,7 @@ void PathCumulFilter::OnBeforeSynchronizePaths() { } } if (FilterSoftSpanQuadraticCost()) { - const SimpleBoundCosts::BoundCost bound_cost = + const BoundCost bound_cost = dimension_.GetQuadraticCostSoftSpanUpperBoundForVehicle(vehicle); if (bound_cost.bound < span_lower_bound) { const int64_t violation = @@ -1676,7 +1676,7 @@ bool PathCumulFilter::AcceptPath(int64_t path_start, int64_t /*chain_start*/, CapProd(vehicle_span_cost_coefficients_[vehicle], min_total_slack)); const int64_t span_lower_bound = CapAdd(total_transit, min_total_slack); if (FilterSoftSpanCost()) { - const SimpleBoundCosts::BoundCost bound_cost = + const BoundCost bound_cost = dimension_.GetSoftSpanUpperBoundForVehicle(vehicle); if (bound_cost.bound < span_lower_bound) { const int64_t violation = CapSub(span_lower_bound, bound_cost.bound); @@ -1685,7 +1685,7 @@ bool PathCumulFilter::AcceptPath(int64_t path_start, int64_t /*chain_start*/, } } if (FilterSoftSpanQuadraticCost()) { - const SimpleBoundCosts::BoundCost bound_cost = + const BoundCost bound_cost = dimension_.GetQuadraticCostSoftSpanUpperBoundForVehicle(vehicle); if (bound_cost.bound < span_lower_bound) { const int64_t violation = CapSub(span_lower_bound, bound_cost.bound); diff --git a/ortools/constraint_solver/routing_lp_scheduling.cc b/ortools/constraint_solver/routing_lp_scheduling.cc index 9a380a865f..f770970895 100644 --- a/ortools/constraint_solver/routing_lp_scheduling.cc +++ b/ortools/constraint_solver/routing_lp_scheduling.cc @@ -1846,7 +1846,7 @@ bool DimensionCumulOptimizerCore::SetRouteCumulConstraints( } // Add soft span cost. if (optimize_costs && dimension_->HasSoftSpanUpperBounds()) { - SimpleBoundCosts::BoundCost bound_cost = + BoundCost bound_cost = dimension_->GetSoftSpanUpperBoundForVehicle(vehicle); if (bound_cost.bound < std::numeric_limits::max() && bound_cost.cost > 0) {