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
This commit is contained in:
committed by
Corentin Le Molgat
parent
13c13048d5
commit
36a29b2ddf
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -2655,7 +2655,7 @@ class TypeRegulationsConstraint : public Constraint {
|
||||
TypeRequirementChecker requirement_checker_;
|
||||
std::vector<Demon*> 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<BoundCost> 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<SimpleBoundCosts>(
|
||||
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<SimpleBoundCosts>(
|
||||
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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<int64_t>::max() &&
|
||||
bound_cost.cost > 0) {
|
||||
|
||||
Reference in New Issue
Block a user