1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

Merge branch 'master' into max-time-feature

# Conflicts:
#	jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java
#	jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java
#	jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/PickupTest.java
#	jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java
#	jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java
This commit is contained in:
oblonski 2017-07-05 10:40:18 +02:00
commit b5998e1d93
No known key found for this signature in database
GPG key ID: 179DE487285680D1
100 changed files with 4103 additions and 2386 deletions

27
.travis.settings.xml Normal file
View file

@ -0,0 +1,27 @@
<!--
~ Licensed to GraphHopper GmbH under one or more contributor
~ license agreements. See the NOTICE file distributed with this work for
~ additional information regarding copyright ownership.
~
~ GraphHopper GmbH licenses this file to you under the Apache License,
~ Version 2.0 (the "License"); you may not use this file except in
~ compliance with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>packagecloud-graphhopper</id>
<password>${env.PACKAGECLOUD_TOKEN}</password>
</server>
</servers>
</settings>

View file

@ -4,3 +4,20 @@ jdk:
- oraclejdk7
- oraclejdk8
deploy:
provider: script
script: "cp .travis.settings.xml $HOME/.m2/settings.xml && mvn deploy"
skip_cleanup: true
on:
tags: true
# do not install anything instead return true via unix command true
install: true
script: mvn clean test
notifications:
email:
- github@graphhopper.com
# enable container-based stack
sudo: false

View file

@ -1,6 +1,15 @@
Change-log
==========
**v1.7.2** @ 2017-06-08
- see [Whats new](https://github.com/graphhopper/jsprit/blob/master/WHATS_NEW.md)
**v1.7.1** @ 2017-05-11
- see [Whats new](https://github.com/graphhopper/jsprit/blob/master/WHATS_NEW.md)
**v1.7** @ 2017-01-12
- see [Whats new](https://github.com/graphhopper/jsprit/blob/master/WHATS_NEW.md)
**v1.6.2** @ 2016-02-02
new features:

View file

@ -1,9 +1,11 @@
The following people have contributed code, bug fixes and ideas.
* [Abraham Gausachs](https://github.com/agausachs)
* [Balage1551](https://github.com/balage1551)
* [Giulio Collura](https://github.com/gcollura)
* [Gwénaël Rault](https://github.com/braktar)
* [Heinrich Filter](https://github.com/HeinrichFilter)
* [jie31best](https://github.com/jie31best)
* Josh Pilkington
* [Julia Loikova](https://github.com/Jullil)
* [muzuro](https://github.com/muzuro)

View file

@ -2,8 +2,9 @@ jsprit
======
[![Build Status](https://travis-ci.org/graphhopper/jsprit.svg?branch=master)](https://travis-ci.org/graphhopper/jsprit)
jsprit is a java based, open source toolkit for solving rich <a href="http://en.wikipedia.org/wiki/Travelling_salesman_problem" target="_blank">traveling salesman</a> (TSP) and <a href="http://neo.lcc.uma.es/vrp/vehicle-routing-problem/" target="_blank">vehicle routing problems</a> (VRP).
It is lightweight, flexible and easy-to-use, and based on a single all-purpose <a href="https://github.com/jsprit/jsprit/wiki/Meta-Heuristic" target="_blank">meta-heuristic</a> currently solving
jsprit is a java based, open source toolkit for solving rich [Traveling Salesman Problems(TSP)](http://en.wikipedia.org/wiki/Travelling_salesman_problem") and [Vehicle Routing Problems(VRP)](http://neo.lcc.uma.es/vrp/vehicle-routing-problem/).
It is lightweight, flexible and easy-to-use, and based on a single all-purpose [meta-heuristic](../docs/Meta-Heuristic.md) currently solving
- Capacitated VRP
- Multiple Depot VRP
- VRP with Time Windows
@ -16,47 +17,45 @@ It is lightweight, flexible and easy-to-use, and based on a single all-purpose <
- Various combination of these types
Setting up the problem, defining additional constraints, modifying the algorithms and visualising the discovered solutions is as easy and handy as
reading classical VRP instances to benchmark your algorithm. It is fit for change and extension due to a modular design and a comprehensive set of unit and integration-tests. [More features ...](https://github.com/jsprit/jsprit/wiki/features)
reading classical VRP instances to benchmark your algorithm. It is fit for change and extension due to a modular design and a comprehensive set of unit and integration-tests. [More features ...](../docs/Features.textile)
##Getting Started and Documentation
Please visit [docs](https://github.com/graphhopper/jsprit/blob/master/docs/Home.md) to learn more. For older versions (<v1.7) use [old-docs](https://github.com/graphhopper/jsprit/blob/%3C1.7/docs/Home.md). The best way to get to know jsprit is by looking at [code examples](https://github.com/graphhopper/jsprit/tree/master/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples).
## Getting Started with Documentation
Please visit [docs](https://github.com/graphhopper/jsprit/blob/master/docs/Home.md) to learn more.The best way to get to know jsprit is by looking at [code examples](https://github.com/graphhopper/jsprit/tree/master/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples).
## Modules and Dependencies
Please read [Notice.md](https://github.com/graphhopper/jsprit/blob/master/NOTICE.md) to get to know the direct dependencies of each module.
##Whats New
## Whats New
jsprit develops fast. Look [here](https://github.com/jsprit/jsprit/blob/master/WHATS_NEW.md) to get to know whats new.
##License
## License
This software is released under [Apache License v2](https://www.apache.org/licenses/LICENSE-2.0).
##Contribution
## Contribution
Any contribution is welcome. Feel free to improve jsprit and make pull requests. If you want to contribute to jsprit (which would be great), fork the project and build your fork, make changes, run your and jsprit's test cases and make a pull request (see [help.github.contribute](https://help.github.com/articles/fork-a-repo) or [stackoverflow.contribute](http://stackoverflow.com/questions/4384776/how-do-i-contribute-to-others-code-in-github) for details).
See who has contributed [here](https://github.com/jsprit/jsprit/blob/master/CONTRIBUTORS.md).
##Acknowledgement
## Acknowledgement
Developing this would be much more difficult without the help of [these companies](https://github.com/graphhopper/jsprit/blob/master/docs/Acknowledgement.md).
##Contact
## Contact
####Mailing List:
In the [mailing list](https://discuss.graphhopper.com/) ([old mailing list](https://groups.google.com/group/jsprit-mailing-list)) you can discuss jsprit related issues and you will probably get answers to your questions.
#### Mailing List:
In the [Graphhopper Forum ](https://discuss.graphhopper.com/) ([Also you can see the old mailing list](https://groups.google.com/group/jsprit-mailing-list)) you can discuss jsprit related issues and you will probably get answers to your questions.
####Stackoverflow:
#### Stackoverflow:
You can also use [stackoverflow](http://stackoverflow.com/questions/tagged/jsprit) to discuss your issues. Tag it with <em>jsprit</em> then it is easier to keep track of your topic.
####Issue Tracker:
#### Issue Tracker:
For bugs, feature requests or similar use the [issue tracker](https://github.com/jsprit/jsprit/issues).
####Email:
If you cannot get help in the mailing list or you just do not want to discuss your topic publicly, send an email to:
info@graphhopper.com
#### Email:
If you cannot get help in the mailing list or you just do not want to discuss your topic publicly, [contact us via mail](https://graphhopper.com/#contact)
##About
## About
The jsprit-project has been created by [Stefan Schröder](https://github.com/oblonski) and is maintained by [GraphHopper](https://graphhopper.com/). It is motivated by two issues.
First, you can find vehicle routing problems **everywhere** in the world of distributing and moving things and people. This probably explains why there is an almost endless list of papers and algorithms to tackle these problems. However, there are only [very few open source implementations](https://github.com/graphhopper/jsprit/blob/master/docs/Other-Projects.md) and even fewer projects that can deal with real world problems that usually have many side-constraints.

View file

@ -1,15 +1,30 @@
WHATS NEW
==========
------------------------------
<b>??</b> new release **v1.7**
<b>2017-06-08</b> new release **v1.7.2**
- one can now set custom properties/user defined data (see pr: https://github.com/graphhopper/jsprit/pull/348)
For example, if one wants to enrich a service with an arbitrary number of custom properties, set a map like this:
<pre><code>Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setUserData(new HashMap&lt;String, Object&gt;()).build();</code></pre>
<b>2017-05-11</b> new release **v1.7.1**
- determine [reasons for unassigned jobs](https://github.com/graphhopper/jsprit/issues/180)
- extend priority levels from 3 to 10 levels
- a number of minor improvements
<b>2017-01-12</b> new release **v1.7**
- move packages to [graphhopper.com](https://graphhopper.com/)
- change license from GPLv3 to [Apache v2](https://github.com/graphhopper/jsprit/blob/master/LICENSE.md) to make it even more attractive for other developers and their commercial applications
- pushed binaries to maven central, i.e. made it better accessible and we get rid of our own repo
- outsourced various io operations, e.g. reading writing problem/algorithm to a new module called [jsprit-io](https://github.com/graphhopper/jsprit/tree/master/jsprit-io). this way the core is even more lightweight and less dependent on other libraries
- switched from log4j to the [logger facade slf4j](http://www.slf4j.org/) to allow developers to plugin the logger of their choice
- made it [much more memory efficient](https://github.com/graphhopper/jsprit/issues/230) for large problems
- fixed [memory leak](https://github.com/graphhopper/jsprit/pull/282)
- add [priority feature](https://github.com/graphhopper/jsprit/issues/242)
- [refine exceptions](https://github.com/graphhopper/jsprit/issues/251) to get a clear separation of IllegalArgument and [IllegalState](https://stackoverflow.com/questions/12698275/whats-the-intended-use-of-illegalstateexception)
- many further improvements (see https://github.com/graphhopper/jsprit/issues?q=is%3Aissue+is%3Aclosed)
<b>2016-02-02</b> new release **v1.6.2**

View file

@ -1,9 +1,9 @@
- Capacitated VRP<a href="https://github.com/jsprit/jsprit/wiki/Simple-Example"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"> </a><a href="https://github.com/jsprit/jsprit/wiki/Network-Based-VRPs"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/network_small.png" title="Code Example - NetworkBased VRP"></a><a href="https://github.com/jsprit/jsprit/wiki/Benchmark-CVRP"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/1372278707_table_chart.png" title="Benchmark"> </a>
- Multiple Depot VRP <a href="https://github.com/jsprit/jsprit/wiki/Multiple-Depot-VRP"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a><a href="https://github.com/jsprit/jsprit/wiki/Benchmark-MDVRP"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/1372278707_table_chart.png" title="Benchmark"></a>
- VRP with Time Windows<a href="https://github.com/jsprit/jsprit/wiki/VRP-with-time-windows-example"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a><a href="https://github.com/jsprit/jsprit/wiki/Benchmark-VRPTW"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/1372278707_table_chart.png" title="Benchmark"></a>
- VRP with Backhauls (Deliveries first)<a href="https://github.com/jsprit/jsprit/wiki/VRP-with-backhauls-example"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a>
- VRP with Backhauls (mixed Pickups and Deliveries)<a href="https://github.com/jsprit/jsprit/wiki/VRP-with-depot-bounded-pickups-and-deliveries"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a>
- VRP with Pickups and Deliveries<a href="https://github.com/jsprit/jsprit/wiki/VRP-with-pickups-and-deliveries"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a>
- VRP with Heterogeneous Fleet<a href="https://github.com/jsprit/jsprit/wiki/Heterogeneous-fleet"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a><a href="https://github.com/jsprit/jsprit/wiki/Benchmark-VRPH"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/1372278707_table_chart.png" title="Benchmark"></a>
- Traveling Salesman Problem<a href="https://github.com/jsprit/jsprit/wiki/Traveling-Salesman-Problem"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a>
- Dial-a-Ride Problem<a href="https://github.com/jsprit/jsprit/wiki/Dial-a-Ride-Problem"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a>
- Capacitated VRP<a href="https://github.com/graphhopper/jsprit/blob/master/docs/Simple-Example.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"> </a><a href="https://github.com/jsprit/jsprit/wiki/Network-Based-VRPs.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/network_small.png" title="Code Example - NetworkBased VRP"></a><a href="https://github.com/jsprit/jsprit/wiki/Benchmark-CVRP.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/1372278707_table_chart.png" title="Benchmark"> </a>
- Multiple Depot VRP <a href="https://github.com/graphhopper/jsprit/blob/master/docs/Multiple-Depot-VRP.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a><a href="https://github.com/jsprit/jsprit/wiki/Benchmark-MDVRP.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/1372278707_table_chart.png" title="Benchmark"></a>
- VRP with Time Windows<a href="https://github.com/graphhopper/jsprit/blob/master/docs/VRP-with-time-windows-example.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a><a href="https://github.com/jsprit/jsprit/wiki/Benchmark-VRPTW"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/1372278707_table_chart.png" title="Benchmark"></a>
- VRP with Backhauls (Deliveries first)<a href="https://github.com/graphhopper/jsprit/blob/master/docs/VRP-with-backhauls-example.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a>
- VRP with Backhauls (mixed Pickups and Deliveries)<a href="https://github.com/graphhopper/jsprit/blob/master/docs/VRP-with-depot-bounded-pickups-and-deliveries.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a>
- VRP with Pickups and Deliveries<a href="https://github.com/graphhopper/jsprit/blob/master/docs/Vrp-with-pickups-and-deliveries.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a>
- VRP with Heterogeneous Fleet<a href="https://github.com/graphhopper/jsprit/blob/master/docs/Heterogeneous-Fleet.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a><a href="https://github.com/jsprit/jsprit/wiki/Benchmark-VRPH"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/1372278707_table_chart.png" title="Benchmark"></a>
- Traveling Salesman Problem<a href="https://github.com/jsprit/jsprit/wiki/Traveling-Salesman-Problem.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a>
- Dial-a-Ride Problem<a href="https://github.com/jsprit/jsprit/wiki/Dial-a-Ride-Problem.md"><img src="https://github.com/jsprit/misc-rep/raw/master/wiki-images/examples_small.png" title="Code Example"></a>

View file

@ -1 +1 @@
You model a dial-a-ride problem much like a vehicle routing problem with pickups and deliveries. The capacity of vehicles can be interpreted as number of seats available. A shipment is here understood as a ride from one location to another (probably you want the shipment to have a capacity-demand of 1). See [VRP with pickups and deliveries](https://github.com/jsprit/jsprit/wiki/VRP-with-pickups-and-deliveries).
You model a dial-a-ride problem much like a vehicle routing problem with pickups and deliveries. The capacity of vehicles can be interpreted as number of seats available. A shipment is here understood as a ride from one location to another (probably you want the shipment to have a capacity-demand of 1). See [VRP with pickups and deliveries](../docs/Vrp-with-pickups-and-deliveries.md).

View file

@ -1,7 +1,7 @@
####Requirements
jsprit requires the Java 2 platform (JDK version 1.7.0 or later).
#### Requirements
jsprit requires Java 1.7.0 or later.
####Modules
#### Modules
jsprit is a multi-module project and consists of:
- jsprit-core
- jsprit-analysis
@ -9,17 +9,20 @@ jsprit is a multi-module project and consists of:
- jsprit-examples
- jsprit-io
####Maven way
#### Maven way
If you want to use the latest release of jsprit-core, add the following lines to your pom:
<pre><code>&lt;dependency&gt;
```
&lt;dependency&gt;
&lt;groupId&gt;com.graphhopper&lt;/groupId&gt;
&lt;artifactId&gt;jsprit-core&lt;/artifactId&gt;
&lt;version&gt;1.7-RC1&lt;/version&gt;
&lt;version&gt;{version}&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
```
####Build yourself
Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core)
#### Build yourself
If you want to build the master branch yourself, do this:
```
@ -28,7 +31,7 @@ cd jsprit
mvn clean install
```
####If you do not have an IDE and you want to use Maven
#### If you do not have an IDE and you want to use Maven
the following documentation is recommended:
@ -37,6 +40,7 @@ the following documentation is recommended:
Here you learn to setup the Java environment and an Integrated Development Environment (IDE). In the subsection <em>Adding Jars to your Project</em> you learn to integrate external libraries in your project. Just copy/paste the above jsprit releases/snapshots to your pom.xml instead of the GeoTools-artifacts.
#### If you do not want Maven
to manage your dependencies, go to [maven central](https://search.maven.org/), search for jsprit and download the latest binaries to put them into your classpath.
Go ahead and show me a [simple example](Simple-Example.md) of how to setup and solve a vehicle routing problem.

View file

@ -1,25 +1,25 @@
#### [Multiple Depot VRP](Multiple-Depot-VRP)
#### [Multiple Depot VRP](Multiple-Depot-VRP.md)
- setting up a VRP with Multiple Depots
- defining depots, vehicles and their types
- dealing with finite fleet size
#### [VRP with time windows](VRP-with-time-windows-example)
#### [VRP with time windows](VRP-with-time-windows-example.md)
- defining and creating vehicles and their types
- defining services with time-windows and service times
- defining a problem with infinite fleet-size
- reading, creating and running an algorithm
#### [VRP with backhauls](VRP-with-backhauls-example)
#### [VRP with backhauls](VRP-with-backhauls-example.md)
- defining and creating pickup and deliveries
- defining backhaul constraint
#### [VRP with backhauls (with mixed pickup and deliveries)](VRP-with-depot-bounded-pickups-and-deliveries)
#### [VRP with backhauls (with mixed pickup and deliveries)](VRP-with-depot-bounded-pickups-and-deliveries.md)
- defining and creating depot-bounded pickups and deliveries
#### [VRP with pickup and delivieries](VRP-with-pickups-and-deliveries)
#### [VRP with pickup and delivieries](Vrp-with-pickups-and-deliveries.md)
- defining and creating pickups and deliveries
#### [VRP with heterogeneous fleet](Heterogeneous-Fleet)
#### [VRP with heterogeneous fleet](Heterogeneous-Fleet.md)
- illustrating different problem types,
- specifying heterogeneous fleet with its vehicles and vehicle-types,
- specifying the algorithm,

View file

@ -16,7 +16,7 @@ First, build a vehicle with its vehicle-type:
<pre><code>/*
* get a vehicle type-builder and build a type with the typeId "vehicleType" and a capacity of 2
* you are free to add an arbitrary number of capacity dimensions with .addCacpacityDimension(dimensionIndex,dimensionValue)
* you are free to add an arbitrary number of capacity dimensions with .addCapacityDimension(dimensionIndex,dimensionValue)
*/
final int WEIGHT_INDEX = 0;
VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(WEIGHT_INDEX,2);

View file

@ -108,4 +108,4 @@ Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions(
VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions);
</code></pre>
Please visit <a href="https://github.com/jsprit/jsprit/wiki/Simple-Example">Simple Example</a> to get to know how you can analyse the solution.
Please visit [Simple Example](https://github.com/graphhopper/jsprit/blob/master/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/SimpleExample.java) to get to know how you can analyse the solution.

View file

@ -2,8 +2,11 @@ It is assumed that you know the basics of the [applied algorithm](Meta-Heuristic
removed job is re-inserted into the ruined solution again (one after another). To actually insert a job, the algorithm
calculates its "best" insertion position. This implies also to check the feasibility of the insertion step
which is in turn dependent on constraints (such as capacity constraints).
jsprit knows hard and soft constraints. Whereas hard constraints must be met and cannot be broken, soft constraints
are always fulfilled but uses penalties to express "good" and "bad" insertions.
## jsprit knows hard and soft constraints.
- Hard constraints must be met and cannot be broken
- soft constraints are always fulfilled but uses penalties to express "good" and "bad" insertions.
jsprit comes with built-in or default constraints (such as capacity and time-window constraints) and allows you to add
custom constraints. However, you can also disable the default constraints. To add custom constraints use
@ -44,7 +47,7 @@ There are hard constraints at two different levels: at route and activity level.
A route is basically a sequence of activities. Each route has a start- and an end-activity, and in between other activities of type <code>core.problem.solution.route.activity.TourActivity</code>.
###<code>core.problem.constraint.HardRouteConstraint</code>
### <code>core.problem.constraint.HardRouteConstraint</code>
A HardRouteConstraint indicates whether a specified job can be inserted into an existing route (along with a specified vehicle). To define it you need to implement the HardRouteConstraint-interface:
<pre><code>HardRouteConstraint constraint = new HardRouteConstraint(){
@ -61,7 +64,7 @@ The JobInsertionContext tells you the context of the insertion step, i.e. the sp
a specified route (<code>iContext.getRoute()</code>) as well as the vehicle
that should be employed on that route (<code>iContext.getNewVehicle()</code>).
####Example:
#### Example:
Assume a vehicle with id="1" is not allowed to serve a job with id="job1" (since it is for example too big to access the customer location). Such a constraint can be easily defined as follows:
<pre><code>final Job jobWithAccessConstraint = routingProblem.getJobs().get("job1");

View file

@ -20,7 +20,7 @@
<parent>
<groupId>com.graphhopper</groupId>
<artifactId>jsprit</artifactId>
<version>1.6.3-SNAPSHOT</version>
<version>1.7.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jsprit-analysis</artifactId>

View file

@ -1,475 +0,0 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.analysis.toolbox;
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithmFactory;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import com.graphhopper.jsprit.core.util.BenchmarkInstance;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ComputationalLaboratory {
public static interface LabListener {
}
/**
* Listener-interface to listen to calculation.
* <p>
* <p>Note that calculations are run concurrently, i.e. a unique task that is distributed to an available thread is
* {algorithm, instance, run}.
*
* @author schroeder
*/
public static interface CalculationListener extends LabListener {
public void calculationStarts(final BenchmarkInstance p, final String algorithmName, final VehicleRoutingAlgorithm algorithm, final int run);
public void calculationEnds(final BenchmarkInstance p, final String algorithmName, final VehicleRoutingAlgorithm algorithm, final int run, final Collection<VehicleRoutingProblemSolution> solutions);
}
public static interface LabStartsAndEndsListener extends LabListener {
public void labStarts(List<BenchmarkInstance> instances, int noAlgorithms, int runs);
public void labEnds();
}
/**
* Collects whatever indicators you require by algorithmName, instanceName, run and indicator.
*
* @author schroeder
*/
public static class DataCollector {
public static class Key {
private String instanceName;
private String algorithmName;
private int run;
private String indicatorName;
public Key(String instanceName, String algorithmName, int run, String indicatorName) {
super();
this.instanceName = instanceName;
this.algorithmName = algorithmName;
this.run = run;
this.indicatorName = indicatorName;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((algorithmName == null) ? 0 : algorithmName
.hashCode());
result = prime
* result
+ ((indicatorName == null) ? 0 : indicatorName
.hashCode());
result = prime
* result
+ ((instanceName == null) ? 0 : instanceName.hashCode());
result = prime * result + run;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Key other = (Key) obj;
if (algorithmName == null) {
if (other.algorithmName != null)
return false;
} else if (!algorithmName.equals(other.algorithmName))
return false;
if (indicatorName == null) {
if (other.indicatorName != null)
return false;
} else if (!indicatorName.equals(other.indicatorName))
return false;
if (instanceName == null) {
if (other.instanceName != null)
return false;
} else if (!instanceName.equals(other.instanceName))
return false;
if (run != other.run)
return false;
return true;
}
public String getInstanceName() {
return instanceName;
}
public String getAlgorithmName() {
return algorithmName;
}
public int getRun() {
return run;
}
public String getIndicatorName() {
return indicatorName;
}
@Override
public String toString() {
return "[algorithm=" + algorithmName + "][instance=" + instanceName + "][run=" + run + "][indicator=" + indicatorName + "]";
}
}
private final static String SOLUTION_INDICATOR_NAME = "vehicle-routing-problem-solution";
private ConcurrentHashMap<Key, Double> data = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, Double>();
private ConcurrentHashMap<Key, VehicleRoutingProblemSolution> solutions = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, VehicleRoutingProblemSolution>();
/**
* Adds a single date by instanceName, algorithmName, run and indicatorName.
* <p>If there is already an entry for this instance, algorithm, run and indicatorName, it is overwritten.
*
* @param instanceName
* @param algorithmName
* @param run
* @param indicatorName
* @param value
*/
public void addDate(String instanceName, String algorithmName, int run, String indicatorName, double value) {
if (indicatorName.equals(SOLUTION_INDICATOR_NAME))
throw new IllegalArgumentException(indicatorName + " is already used internally. please choose another indicator-name.");
Key key = new Key(instanceName, algorithmName, run, indicatorName);
data.put(key, value);
}
public void addSolution(String instanceName, String algorithmName, int run, VehicleRoutingProblemSolution solution) {
Key key = new Key(instanceName, algorithmName, run, SOLUTION_INDICATOR_NAME);
solutions.put(key, solution);
}
/**
* Returns a collections of indicator values representing the calculated values of individual runs.
*
* @param instanceName
* @param algorithmName
* @param indicator
* @return
*/
public Collection<Double> getData(String instanceName, String algorithmName, String indicator) {
List<Double> values = new ArrayList<Double>();
for (Key key : data.keySet()) {
if (key.getAlgorithmName().equals(algorithmName) && key.getInstanceName().equals(instanceName) && key.getIndicatorName().equals(indicator)) {
values.add(data.get(key));
}
}
return values;
}
/**
* Returns indicator value.
*
* @param instanceName
* @param algorithmName
* @param run
* @param indicator
* @return
*/
public Double getDate(String instanceName, String algorithmName, int run, String indicator) {
return data.get(new Key(instanceName, algorithmName, run, indicator));
}
public VehicleRoutingProblemSolution getSolution(String instanceName, String algorithmName, int run) {
return solutions.get(new Key(instanceName, algorithmName, run, "solution"));
}
/**
* Returns all keys that have been created. A key is a unique combination of algorithmName, instanceName, run and indicator.
*
* @return
*/
public Set<Key> getDataKeySet() {
return data.keySet();
}
public Set<Key> getSolutionKeySet() {
return solutions.keySet();
}
public VehicleRoutingProblemSolution getSolution(Key solutionKey) {
return solutions.get(solutionKey);
}
public Collection<VehicleRoutingProblemSolution> getSolutions() {
return solutions.values();
}
/**
* Returns date associated to specified key.
*
* @param key
* @return
*/
public Double getData(Key key) {
return data.get(key);
}
}
private static class Algorithm {
private String name;
private VehicleRoutingAlgorithmFactory factory;
public Algorithm(String name, VehicleRoutingAlgorithmFactory factory) {
super();
this.name = name;
this.factory = factory;
}
}
private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>();
private int runs = 1;
private Collection<CalculationListener> listeners = new ArrayList<ComputationalLaboratory.CalculationListener>();
private Collection<LabStartsAndEndsListener> startsAndEndslisteners = new ArrayList<LabStartsAndEndsListener>();
private List<Algorithm> algorithms = new ArrayList<ComputationalLaboratory.Algorithm>();
private Set<String> algorithmNames = new HashSet<String>();
private Set<String> instanceNames = new HashSet<String>();
private int threads = 1;
public ComputationalLaboratory() {
}
/**
* Adds algorithmFactory by name.
*
* @param name
* @param factory
* @throws IllegalStateException if there is already an algorithmFactory with the same name
*/
public void addAlgorithmFactory(String name, VehicleRoutingAlgorithmFactory factory) {
if (algorithmNames.contains(name))
throw new IllegalStateException("there is already a algorithmFactory with the same name (algorithmName=" + name + "). unique names are required.");
algorithms.add(new Algorithm(name, factory));
algorithmNames.add(name);
}
public Collection<String> getAlgorithmNames() {
return algorithmNames;
}
public Collection<String> getInstanceNames() {
return instanceNames;
}
/**
* Adds instance by name.
*
* @param name
* @param problem
* @throws IllegalStateException if there is already an instance with the same name.
*/
public void addInstance(String name, VehicleRoutingProblem problem) {
if (benchmarkInstances.contains(name))
throw new IllegalStateException("there is already an instance with the same name (instanceName=" + name + "). unique names are required.");
benchmarkInstances.add(new BenchmarkInstance(name, problem, null, null));
instanceNames.add(name);
}
/**
* Adds instance.
*
* @param instance the instance to be added
* @throws IllegalStateException if there is already an instance with the same name.
*/
public void addInstance(BenchmarkInstance instance) {
if (benchmarkInstances.contains(instance.name))
throw new IllegalStateException("there is already an instance with the same name (instanceName=" + instance.name + "). unique names are required.");
benchmarkInstances.add(instance);
instanceNames.add(instance.name);
}
/**
* Adds collection of instances.
*
* @param instances collection of instances to be added
* @throws IllegalStateException if there is already an instance with the same name.
*/
public void addAllInstances(Collection<BenchmarkInstance> instances) {
for (BenchmarkInstance i : instances) {
addInstance(i);
}
}
/**
* Adds instance by name, and with best known results.
*
* @param name
* @param problem
* @throws IllegalStateException if there is already an instance with the same name.
*/
public void addInstance(String name, VehicleRoutingProblem problem, Double bestKnownResult, Double bestKnownVehicles) {
addInstance(new BenchmarkInstance(name, problem, bestKnownResult, bestKnownVehicles));
}
/**
* Adds listener to listen computational experiments.
*
* @param listener
*/
public void addListener(LabListener listener) {
if (listener instanceof CalculationListener) {
listeners.add((CalculationListener) listener);
}
if (listener instanceof LabStartsAndEndsListener) {
startsAndEndslisteners.add((LabStartsAndEndsListener) listener);
}
}
/**
* Sets nuOfRuns with same algorithm on same instance.
* <p>Default is 1
*
* @param runs
*/
public void setNuOfRuns(int runs) {
this.runs = runs;
}
/**
* Runs experiments.
* <p>
* <p>If nuThreads > 1 it runs them concurrently, i.e. individual runs are distributed to available threads. Therefore
* a unique task is defined by its algorithmName, instanceName and its runNumber.
* <p>If you have one algorithm called "myAlgorithm" and one instance called "myInstance", and you need to run "myAlgorithm" on "myInstance" three times
* with three threads then "myAlgorithm","myInstance",run1 runs on the first thread, "myAlgorithm", "myInstance", run2 on the second etc.
* <p>You can register whatever analysisTool you require by implementing and registering CalculationListener. Then your tool is informed just
* before a calculation starts as well as just after a calculation has been finished.
*
* @throws IllegalStateException if either no algorithm or no instance has been specified
* @see CalculationListener
*/
public void run() {
if (algorithms.isEmpty()) {
throw new IllegalStateException("no algorithm specified. at least one algorithm needs to be specified.");
}
if (benchmarkInstances.isEmpty()) {
throw new IllegalStateException("no instance specified. at least one instance needs to be specified.");
}
informStart();
System.out.println("start benchmarking [nuAlgorithms=" + algorithms.size() + "][nuInstances=" + benchmarkInstances.size() + "][runsPerInstance=" + runs + "]");
double startTime = System.currentTimeMillis();
ExecutorService executor = Executors.newFixedThreadPool(threads);
for (final Algorithm algorithm : algorithms) {
for (final BenchmarkInstance p : benchmarkInstances) {
for (int run = 0; run < runs; run++) {
final int r = run;
try {
executor.submit(new Runnable() {
@Override
public void run() {
runAlgorithm(p, algorithm, r + 1);
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
try {
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("benchmarking done [time=" + (System.currentTimeMillis() - startTime) / 1000 + "sec]");
informEnd();
}
private void informEnd() {
for (LabStartsAndEndsListener l : startsAndEndslisteners) {
l.labEnds();
}
}
private void informStart() {
for (LabStartsAndEndsListener l : startsAndEndslisteners) {
l.labStarts(benchmarkInstances, algorithms.size(), runs);
}
}
/**
* Sets number of threads.
* <p>By default: <code>nuThreads = Runtime.getRuntime().availableProcessors()+1</code>
*
* @param threads
*/
public void setThreads(int threads) {
this.threads = threads;
}
private void runAlgorithm(BenchmarkInstance p, Algorithm algorithm, int run) {
System.out.println("[algorithm=" + algorithm.name + "][instance=" + p.name + "][run=" + run + "][status=start]");
VehicleRoutingAlgorithm vra = algorithm.factory.createAlgorithm(p.vrp);
informCalculationStarts(p, algorithm.name, vra, run);
Collection<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();
System.out.println("[algorithm=" + algorithm.name + "][instance=" + p.name + "][run=" + run + "][status=finished]");
informCalculationsEnds(p, algorithm.name, vra, run, solutions);
}
private void informCalculationStarts(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run) {
for (CalculationListener l : listeners) l.calculationStarts(p, name, vra, run);
}
private void informCalculationsEnds(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run,
Collection<VehicleRoutingProblemSolution> solutions) {
for (CalculationListener l : listeners) l.calculationEnds(p, name, vra, run, solutions);
}
}

View file

@ -0,0 +1,162 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.analysis.toolbox;
import com.graphhopper.jsprit.core.algorithm.SearchStrategy;
import com.graphhopper.jsprit.core.algorithm.listener.AlgorithmEndsListener;
import com.graphhopper.jsprit.core.algorithm.listener.IterationStartsListener;
import com.graphhopper.jsprit.core.algorithm.listener.StrategySelectedListener;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.*;
/**
* Created by schroeder on 27/04/17.
*/
public class StrategyAnalyser implements AlgorithmEndsListener, StrategySelectedListener, IterationStartsListener {
public static class Strategy {
private final String id;
private int selected = 0;
private int improved = 0;
private int countNewSolution = 0;
private List<Double> improvements = new ArrayList<>();
public Strategy(String id) {
this.id = id;
}
public void selected() {
selected++;
}
public void improvedSolution(double improvement) {
improved++;
improvements.add(improvement);
}
public void newSolution() {
countNewSolution++;
}
public String getId() {
return id;
}
public int getCountSelected() {
return selected;
}
public int getCountImproved() {
return improved;
}
public int getCountNewSolution() {
return countNewSolution;
}
public List<Double> getImprovements() {
return improvements;
}
}
private Map<String, Strategy> strategyMap = new HashMap<>();
private Collection<VehicleRoutingProblemSolution> last;
private Writer out;
@Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
last = new ArrayList<>(solutions);
}
@Override
public void informSelectedStrategy(SearchStrategy.DiscoveredSolution discoveredSolution, VehicleRoutingProblem vehicleRoutingProblem, Collection<VehicleRoutingProblemSolution> vehicleRoutingProblemSolutions) {
String strategyId = discoveredSolution.getStrategyId();
if (!strategyMap.containsKey(strategyId)) {
strategyMap.put(strategyId, new Strategy(strategyId));
}
Strategy strategy = strategyMap.get(strategyId);
strategy.selected();
if (discoveredSolution.isAccepted()) strategy.newSolution();
if (isBetter(vehicleRoutingProblemSolutions, last)) {
strategy.improvedSolution(getImprovement(vehicleRoutingProblemSolutions, last));
}
}
public void setOutWriter(Writer out) {
this.out = out;
}
@Override
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
if (out == null) out = new PrintWriter(System.out);
try {
for (String stratId : strategyMap.keySet()) {
StrategyAnalyser.Strategy strategy = strategyMap.get(stratId);
out.write("id: " + stratId + ", #selected: " + strategy.getCountSelected() + ", #newSolutions: " + strategy.getCountNewSolution()
+ ", #improvedSolutions: " + strategy.getCountImproved() + ", improvements: " + strategy.getImprovements().toString() + "\n");
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
out.flush();
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
private double getImprovement(Collection<VehicleRoutingProblemSolution> vehicleRoutingProblemSolutions, Collection<VehicleRoutingProblemSolution> last) {
for (VehicleRoutingProblemSolution solution : vehicleRoutingProblemSolutions) {
for (VehicleRoutingProblemSolution lastSolution : last) {
if (solution.getCost() < lastSolution.getCost())
return Math.round(lastSolution.getCost() - solution.getCost());
}
}
return 0;
}
private boolean isBetter(Collection<VehicleRoutingProblemSolution> vehicleRoutingProblemSolutions, Collection<VehicleRoutingProblemSolution> last) {
for (VehicleRoutingProblemSolution solution : vehicleRoutingProblemSolutions) {
for (VehicleRoutingProblemSolution lastSolution : last) {
if (solution.getCost() < lastSolution.getCost()) return true;
}
}
return false;
}
public Map<String, Strategy> getStrategies() {
return strategyMap;
}
}

View file

@ -1,257 +0,0 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.analysis.util;
import com.graphhopper.jsprit.core.util.BenchmarkResult;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
public class HtmlBenchmarkTableWriter implements BenchmarkWriter {
private String filename;
public HtmlBenchmarkTableWriter(String filename) {
this.filename = filename;
}
@Override
public void write(Collection<BenchmarkResult> results) {
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(filename)));
writer.write(openTable() + newline());
//table head
writer.write(openRow() + newline());
writer.write(head("inst") + newline());
writer.write(head("runs") + newline());
writer.write(head("&Oslash; time [sec]") + newline());
writer.write(head("results", 4));
writer.write(head("vehicles", 4));
writer.write(head("res*") + newline());
writer.write(head("veh*") + newline());
writer.write(closeRow() + newline());
writer.write(openRow() + newline());
writer.write(head("") + newline());
writer.write(head("") + newline());
writer.write(head("") + newline());
writer.write(head("best") + newline());
writer.write(head("avg") + newline());
writer.write(head("worst") + newline());
writer.write(head("stdev") + newline());
writer.write(head("best") + newline());
writer.write(head("avg") + newline());
writer.write(head("worst") + newline());
writer.write(head("stdev") + newline());
writer.write(head("") + newline());
writer.write(head("") + newline());
writer.write(closeRow() + newline());
//data
double sum_avg_time = 0.0;
double sum_best_result = 0.0;
double sum_avg_result = 0.0;
double sum_worst_result = 0.0;
double sum_dev_result = 0.0;
double sum_best_veh = 0.0;
double sum_avg_veh = 0.0;
double sum_worst_veh = 0.0;
double sum_dev_veh = 0.0;
Integer runs = null;
Double sum_res_star = null;
Double sum_veh_star = null;
for (BenchmarkResult result : results) {
if (runs == null) runs = result.runs;
writer.write(openRow() + newline());
writer.write(date(result.instance.name) + newline());
writer.write(date(Integer.valueOf(result.runs).toString()) + newline());
Double avg_time = round(result.getTimesStats().getMean(), 2);
writer.write(date(Double.valueOf(avg_time).toString()) + newline());
//bestRes
Double best_result = round(result.getResultStats().getMin(), 2);
writer.write(date(Double.valueOf(best_result).toString()) + newline());
//avgRes
Double avg_result = round(result.getResultStats().getMean(), 2);
writer.write(date(Double.valueOf(avg_result).toString()) + newline());
//worstRes
Double worst_result = round(result.getResultStats().getMax(), 2);
writer.write(date(Double.valueOf(worst_result).toString()) + newline());
//stdevRes
Double std_result = round(result.getResultStats().getStandardDeviation(), 2);
writer.write(date(Double.valueOf(std_result).toString()) + newline());
//bestVeh
Double best_vehicle = round(result.getVehicleStats().getMin(), 2);
writer.write(date(Double.valueOf(best_vehicle).toString()) + newline());
//avgVeh
Double avg_vehicle = round(result.getVehicleStats().getMean(), 2);
writer.write(date(Double.valueOf(avg_vehicle).toString()) + newline());
//worstVeh
Double worst_vehicle = round(result.getVehicleStats().getMax(), 2);
writer.write(date(Double.valueOf(worst_vehicle).toString()) + newline());
//stdevVeh
Double std_vehicle = round(result.getVehicleStats().getStandardDeviation(), 2);
writer.write(date(Double.valueOf(std_vehicle).toString()) + newline());
//bestKnownRes
writer.write(date("" + result.instance.bestKnownResult + newline()));
//bestKnownVeh
writer.write(date("" + result.instance.bestKnownVehicles + newline()));
writer.write(closeRow() + newline());
sum_avg_time += avg_time;
sum_best_result += best_result;
sum_avg_result += avg_result;
sum_worst_result += worst_result;
sum_dev_result += std_result;
sum_best_veh += best_vehicle;
sum_avg_veh += avg_vehicle;
sum_worst_veh += worst_vehicle;
sum_dev_veh += std_vehicle;
if (result.instance.bestKnownResult != null) {
if (sum_res_star == null) sum_res_star = result.instance.bestKnownResult;
else sum_res_star += result.instance.bestKnownResult;
}
if (result.instance.bestKnownVehicles != null) {
if (sum_veh_star == null) sum_veh_star = result.instance.bestKnownVehicles;
else sum_veh_star += result.instance.bestKnownVehicles;
}
}
writer.write(openRow() + newline());
writer.write(date("&Oslash;") + newline());
writer.write(date("" + runs) + newline());
Double average_time = round(sum_avg_time / (double) results.size(), 2);
writer.write(date(Double.valueOf(average_time).toString()) + newline());
//bestRes
writer.write(date(Double.valueOf(round(sum_best_result / (double) results.size(), 2)).toString()) + newline());
//avgRes
Double average_result = round(sum_avg_result / (double) results.size(), 2);
writer.write(date(Double.valueOf(average_result).toString()) + newline());
//worstRes
writer.write(date(Double.valueOf(round(sum_worst_result / (double) results.size(), 2)).toString()) + newline());
//stdevRes
writer.write(date(Double.valueOf(round(sum_dev_result / (double) results.size(), 2)).toString()) + newline());
//bestVeh
writer.write(date(Double.valueOf(round(sum_best_veh / (double) results.size(), 2)).toString()) + newline());
//avgVeh
Double average_vehicles = round(sum_avg_veh / (double) results.size(), 2);
writer.write(date(Double.valueOf(average_vehicles).toString()) + newline());
//worstVeh
writer.write(date(Double.valueOf(round(sum_worst_veh / (double) results.size(), 2)).toString()) + newline());
//stdevVeh
writer.write(date(Double.valueOf(round(sum_dev_veh / (double) results.size(), 2)).toString()) + newline());
//bestKnownRes
Double delta_res = null;
if (sum_res_star != null) {
writer.write(date(Double.valueOf(round(sum_res_star.doubleValue() / (double) results.size(), 2)).toString()) + newline());
delta_res = (sum_avg_result / sum_res_star - 1) * 100;
} else writer.write(date("null") + newline());
//bestKnownVeh
Double delta_veh = null;
if (sum_veh_star != null) {
writer.write(date(Double.valueOf(round(sum_veh_star.doubleValue() / (double) results.size(), 2)).toString()) + newline());
delta_veh = (sum_avg_veh - sum_veh_star) / (double) results.size();
} else writer.write(date("null") + newline());
writer.write(closeRow() + newline());
writer.write(closeTable() + newline());
writer.write("avg. percentage deviation to best-known result: " + round(delta_res, 2) + newline() + newline());
writer.write("avg. absolute deviation to best-known vehicles: " + round(delta_veh, 2) + newline());
writer.write(openTable() + newline());
writer.write(openRow() + newline());
writer.write(date("") + newline());
writer.write(date("") + newline());
writer.write(date("") + newline());
writer.write(date("") + newline());
writer.write(date(Double.valueOf(average_time).toString(), "align=\"right\"") + newline());
writer.write(date(Double.valueOf(average_result).toString(), "align=\"right\"") + newline());
writer.write(date(Double.valueOf(average_vehicles).toString(), "align=\"right\"") + newline());
if (delta_res != null) {
writer.write(date(Double.valueOf(round(delta_res, 2)).toString(), "align=\"right\"") + newline());
} else writer.write(date("n.a.") + newline());
if (delta_veh != null) {
writer.write(date(Double.valueOf(round(delta_veh, 2)).toString(), "align=\"right\"") + newline());
} else writer.write(date("n.a.") + newline());
writer.write(closeRow() + newline());
writer.write(closeTable() + newline());
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String head(String string, int i) {
return "<th colspan=\"" + i + "\">" + string + "</th>";
}
private Double round(Double value, int i) {
if (value == null) return null;
long roundedVal = Math.round(value * Math.pow(10, i));
return (double) roundedVal / (double) (Math.pow(10, i));
}
private String head(String head) {
return "<th>" + head + "</th>";
}
private String closeTable() {
return "</table>";
}
private String openTable() {
return "<table>";
}
private String closeRow() {
return "</tr>";
}
private String date(String date) {
return "<td>" + date + "</td>";
}
private String date(String date, String metaData) {
return "<td " + metaData + ">" + date + "</td>";
}
private String newline() {
return "\n";
}
private String openRow() {
return "<tr>";
}
}

View file

@ -21,7 +21,7 @@
<parent>
<groupId>com.graphhopper</groupId>
<artifactId>jsprit</artifactId>
<version>1.6.3-SNAPSHOT</version>
<version>1.7.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jsprit-core</artifactId>

View file

@ -17,6 +17,14 @@
*/
package com.graphhopper.jsprit.core.algorithm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.graphhopper.jsprit.core.algorithm.SearchStrategy.DiscoveredSolution;
import com.graphhopper.jsprit.core.algorithm.listener.SearchStrategyListener;
import com.graphhopper.jsprit.core.algorithm.listener.SearchStrategyModuleListener;
@ -30,11 +38,6 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.util.Solutions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
/**
@ -57,10 +60,9 @@ public class VehicleRoutingAlgorithm {
@Override
public boolean isPrematureBreak(DiscoveredSolution discoveredSolution) {
for (PrematureAlgorithmTermination termination : terminationCriteria) {
if (termination.isPrematureBreak(discoveredSolution)) {
if (termination.isPrematureBreak(discoveredSolution))
return true;
}
}
return false;
}
}
@ -140,30 +142,36 @@ public class VehicleRoutingAlgorithm {
* @param solution the solution to be added
*/
public void addInitialSolution(VehicleRoutingProblemSolution solution) {
// We will make changes so let's make a copy
solution = VehicleRoutingProblemSolution.copyOf(solution);
verify(solution);
initialSolutions.add(solution);
}
private void verify(VehicleRoutingProblemSolution solution) {
int nuJobs = 0;
Set<Job> allJobs = new HashSet<Job>(problem.getJobs().values());
allJobs.removeAll(solution.getUnassignedJobs());
for (VehicleRoute route : solution.getRoutes()) {
nuJobs += route.getTourActivities().getJobs().size();
allJobs.removeAll(route.getTourActivities().getJobs());
if (route.getVehicle().getIndex() == 0)
throw new IllegalStateException("vehicle used in initial solution has no index. probably a vehicle is used that has not been added to the " +
" the VehicleRoutingProblem. only use vehicles that have already been added to the problem.");
for (TourActivity act : route.getActivities()) {
if (act.getIndex() == 0) {
if (act.getIndex() == 0)
throw new IllegalStateException("act in initial solution has no index. activities are created and associated to their job in VehicleRoutingProblem\n." +
" thus if you build vehicle-routes use the jobActivityFactory from vehicle routing problem like that \n" +
" VehicleRoute.Builder.newInstance(knownVehicle).setJobActivityFactory(vrp.getJobActivityFactory).addService(..)....build() \n" +
" then the activities that are created to build the route are identical to the ones used in VehicleRoutingProblem");
}
}
}
if (nuJobs != problem.getJobs().values().size()) {
logger.warn("number of jobs in initial solution ({}) is not equal nuJobs in vehicle routing problem ({})" +
"\n this might yield unintended effects, e.g. initial solution cannot be improved anymore.", nuJobs, problem.getJobs().values().size());
}
solution.getUnassignedJobs().addAll(allJobs);
solution.setCost(getObjectiveFunction().getCosts(solution));
// if (nuJobs != problem.getJobs().values().size()) {
// logger.warn("number of jobs in initial solution ({}) is not equal nuJobs in vehicle routing problem ({})" +
// "\n this might yield unintended effects, e.g. initial solution cannot be improved anymore.", nuJobs, problem.getJobs().values().size());
// }
}
/**
@ -214,7 +222,9 @@ public class VehicleRoutingAlgorithm {
Collection<VehicleRoutingProblemSolution> solutions = new ArrayList<VehicleRoutingProblemSolution>(initialSolutions);
algorithmStarts(problem, solutions);
bestEver = Solutions.bestOf(solutions);
if (logger.isTraceEnabled()) log(solutions);
if (logger.isTraceEnabled()) {
log(solutions);
}
logger.info("iterations start");
for (int i = 0; i < maxIterations; i++) {
iterationStarts(i + 1, problem, solutions);
@ -222,7 +232,9 @@ public class VehicleRoutingAlgorithm {
counter.incCounter();
SearchStrategy strategy = searchStrategyManager.getRandomStrategy();
DiscoveredSolution discoveredSolution = strategy.run(problem, solutions);
if (logger.isTraceEnabled()) log(discoveredSolution);
if (logger.isTraceEnabled()) {
log(discoveredSolution);
}
memorizeIfBestEver(discoveredSolution);
selectedStrategy(discoveredSolution, problem, solutions);
if (terminationManager.isPrematureBreak(discoveredSolution)) {
@ -240,11 +252,15 @@ public class VehicleRoutingAlgorithm {
}
private void addBestEver(Collection<VehicleRoutingProblemSolution> solutions) {
if (bestEver != null) solutions.add(bestEver);
if (bestEver != null) {
solutions.add(bestEver);
}
}
private void log(Collection<VehicleRoutingProblemSolution> solutions) {
for (VehicleRoutingProblemSolution sol : solutions) log(sol);
for (VehicleRoutingProblemSolution sol : solutions) {
log(sol);
}
}
private void log(VehicleRoutingProblemSolution solution) {
@ -277,9 +293,11 @@ public class VehicleRoutingAlgorithm {
private void memorizeIfBestEver(DiscoveredSolution discoveredSolution) {
if (discoveredSolution == null) return;
if (bestEver == null) bestEver = discoveredSolution.getSolution();
else if (discoveredSolution.getSolution().getCost() < bestEver.getCost())
if (bestEver == null) {
bestEver = discoveredSolution.getSolution();
} else if (discoveredSolution.getSolution().getCost() < bestEver.getCost()) {
bestEver = discoveredSolution.getSolution();
}
}
@ -297,11 +315,13 @@ public class VehicleRoutingAlgorithm {
public void addListener(VehicleRoutingAlgorithmListener l) {
algoListeners.addListener(l);
if (l instanceof SearchStrategyListener)
if (l instanceof SearchStrategyListener) {
searchStrategyManager.addSearchStrategyListener((SearchStrategyListener) l);
if (l instanceof SearchStrategyModuleListener)
}
if (l instanceof SearchStrategyModuleListener) {
searchStrategyManager.addSearchStrategyModuleListener((SearchStrategyModuleListener) l);
}
}
private void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
algoListeners.iterationEnds(i, problem, solutions);

View file

@ -25,7 +25,9 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
@ -78,7 +80,6 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList
private final int solutionMemory;
public SchrimpfAcceptance(int solutionMemory, double alpha) {
this.alpha = alpha;
this.solutionMemory = solutionMemory;
@ -110,6 +111,32 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList
return solutionAccepted;
}
public boolean acceptSolution(VehicleRoutingProblemSolution solution, VehicleRoutingProblemSolution newSolution) {
List<VehicleRoutingProblemSolution> solutions = new ArrayList<>();
solutions.add(solution);
boolean solutionAccepted = false;
if (solutions.size() < solutionMemory) {
solutions.add(newSolution);
solutionAccepted = true;
} else {
VehicleRoutingProblemSolution worst = null;
double threshold = getThreshold(currentIteration);
for (VehicleRoutingProblemSolution solutionInMemory : solutions) {
if (worst == null) worst = solutionInMemory;
else if (solutionInMemory.getCost() > worst.getCost()) worst = solutionInMemory;
}
if (worst == null) {
solutions.add(newSolution);
solutionAccepted = true;
} else if (newSolution.getCost() < worst.getCost() + threshold) {
solutions.remove(worst);
solutions.add(newSolution);
solutionAccepted = true;
}
}
return solutionAccepted;
}
@Override
public String toString() {
return "[name=SchrimpfAcceptance][alpha=" + alpha + "]";
@ -136,6 +163,16 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList
this.initialThreshold = initialThreshold;
}
public void setMaxIterations(int maxIteration) {
this.maxIterations = maxIteration;
}
public void incIteration() {
currentIteration++;
}
;
@Override
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
reset();

View file

@ -46,9 +46,7 @@ import com.graphhopper.jsprit.core.util.NoiseMaker;
import com.graphhopper.jsprit.core.util.RandomNumberGeneration;
import com.graphhopper.jsprit.core.util.Solutions;
import java.util.Collection;
import java.util.Properties;
import java.util.Random;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -82,7 +80,9 @@ public class Jsprit {
WORST_BEST("worst_best"),
WORST_REGRET("worst_regret"),
CLUSTER_BEST("cluster_best"),
CLUSTER_REGRET("cluster_regret");
CLUSTER_REGRET("cluster_regret"),
STRING_BEST("string_best"),
STRING_REGRET("string_regret");
String strategyName;
@ -112,6 +112,7 @@ public class Jsprit {
WORST_MAX_SHARE("worst.max_share"),
THRESHOLD_ALPHA("threshold.alpha"),
THRESHOLD_INI("threshold.ini"),
THRESHOLD_INI_ABS("threshold.ini_abs"),
INSERTION_NOISE_LEVEL("insertion.noise_level"),
INSERTION_NOISE_PROB("insertion.noise_prob"),
RUIN_WORST_NOISE_LEVEL("worst.noise_level"),
@ -119,7 +120,12 @@ public class Jsprit {
FAST_REGRET("regret.fast"),
MAX_TRANSPORT_COSTS("max_transport_costs"),
CONSTRUCTION("construction"),
BREAK_SCHEDULING("break_scheduling");
BREAK_SCHEDULING("break_scheduling"),
STRING_K_MIN("string_kmin"),
STRING_K_MAX("string_kmax"),
STRING_L_MIN("string_lmin"),
STRING_L_MAX("string_lmax");
String paraName;
@ -161,6 +167,12 @@ public class Jsprit {
private SolutionAcceptor solutionAcceptor;
private ScoringFunction regretScorer = null;
private Map<SearchStrategy, Double> customStrategies = new HashMap<>();
private VehicleFleetManager fleetManager = null;
public static Builder newInstance(VehicleRoutingProblem vrp) {
return new Builder(vrp);
}
@ -176,10 +188,21 @@ public class Jsprit {
defaults.put(Strategy.RADIAL_REGRET.toString(), ".5");
defaults.put(Strategy.RANDOM_BEST.toString(), ".5");
defaults.put(Strategy.RANDOM_REGRET.toString(), ".5");
defaults.put(Strategy.STRING_BEST.toString(), "0.0");
defaults.put(Strategy.STRING_REGRET.toString(), "0.0");
defaults.put(Parameter.STRING_K_MIN.toString(), "1");
defaults.put(Parameter.STRING_K_MAX.toString(), "6");
defaults.put(Parameter.STRING_L_MIN.toString(), "10");
defaults.put(Parameter.STRING_L_MAX.toString(), "30");
defaults.put(Strategy.WORST_BEST.toString(), "0.");
defaults.put(Strategy.WORST_REGRET.toString(), "1.");
defaults.put(Strategy.CLUSTER_BEST.toString(), "0.");
defaults.put(Strategy.CLUSTER_REGRET.toString(), "1.");
defaults.put(Parameter.FIXED_COST_PARAM.toString(), "0.");
defaults.put(Parameter.VEHICLE_SWITCH.toString(), "true");
defaults.put(Parameter.ITERATIONS.toString(), "2000");
@ -214,6 +237,16 @@ public class Jsprit {
}
public Builder addSearchStrategy(SearchStrategy searchStrategy, double weight) {
customStrategies.put(searchStrategy, weight);
return this;
}
public Builder setVehicleFleetManager(VehicleFleetManager fleetManager) {
this.fleetManager = fleetManager;
return this;
}
public Builder setExecutorService(ExecutorService es, int noThreads) {
this.es = es;
this.noThreads = noThreads;
@ -266,6 +299,11 @@ public class Jsprit {
return this;
}
public Builder setRegretScorer(ScoringFunction scoringFunction) {
this.regretScorer = scoringFunction;
return this;
}
public VehicleRoutingAlgorithm buildAlgorithm() {
return new Jsprit(this).create(vrp);
}
@ -328,6 +366,12 @@ public class Jsprit {
private SolutionAcceptor acceptor;
private ScoringFunction regretScorer;
private final Map<SearchStrategy, Double> customStrategies = new HashMap<>();
private VehicleFleetManager vehicleFleetManager;
private Jsprit(Builder builder) {
this.stateManager = builder.stateManager;
this.constraintManager = builder.constraintManager;
@ -339,16 +383,25 @@ public class Jsprit {
this.random = builder.random;
this.activityInsertion = builder.activityInsertionCalculator;
this.acceptor = builder.solutionAcceptor;
regretScorer = builder.regretScorer;
customStrategies.putAll(builder.customStrategies);
vehicleFleetManager = builder.fleetManager;
}
private void ini(VehicleRoutingProblem vrp) {
if (regretScorer == null) regretScorer = getRegretScorer(vrp);
}
private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
VehicleFleetManager fm;
ini(vrp);
if (vehicleFleetManager == null) {
if (vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)) {
fm = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
vehicleFleetManager = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
} else {
FiniteFleetManagerFactory finiteFleetManagerFactory = new FiniteFleetManagerFactory(vrp.getVehicles());
finiteFleetManagerFactory.setRandom(random);
fm = finiteFleetManagerFactory.createFleetManager();
vehicleFleetManager = finiteFleetManagerFactory.createFleetManager();
}
}
if (stateManager == null) {
@ -368,6 +421,14 @@ public class Jsprit {
}
}
double fixedCostParam = toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()));
IncreasingAbsoluteFixedCosts increasingAbsoluteFixedCosts = null;
if (fixedCostParam > 0d) {
increasingAbsoluteFixedCosts = new IncreasingAbsoluteFixedCosts(vrp.getJobs().size());
increasingAbsoluteFixedCosts.setWeightOfFixCost(fixedCostParam);
constraintManager.addConstraint(increasingAbsoluteFixedCosts);
}
double noiseLevel = toDouble(getProperty(Parameter.INSERTION_NOISE_LEVEL.toString()));
double noiseProbability = toDouble(getProperty(Parameter.INSERTION_NOISE_PROB.toString()));
@ -449,13 +510,23 @@ public class Jsprit {
random)
);
int kMin = toInteger(properties.getProperty(Parameter.STRING_K_MIN.toString()));
int kMax = toInteger(properties.getProperty(Parameter.STRING_K_MAX.toString()));
int lMin = toInteger(properties.getProperty(Parameter.STRING_L_MIN.toString()));
int lMax = toInteger(properties.getProperty(Parameter.STRING_L_MAX.toString()));
final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods);
stringRuin.setNoRoutes(kMin, kMax);
stringRuin.setStringLength(lMin, lMax);
stringRuin.setRandom(random);
AbstractInsertionStrategy regret;
final DefaultScorer scorer;
final ScoringFunction scorer;
boolean fastRegret = Boolean.parseBoolean(getProperty(Parameter.FAST_REGRET.toString()));
if (es != null) {
if(fastRegret){
RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setConcurrentMode(es, noThreads)
.setFastRegret(true)
@ -463,45 +534,45 @@ public class Jsprit {
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build();
scorer = getRegretScorer(vrp);
scorer = regretScorer;
regretInsertion.setScoringFunction(scorer);
regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes());
regret = regretInsertion;
}
else {
RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setConcurrentMode(es, noThreads)
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build();
scorer = getRegretScorer(vrp);
scorer = regretScorer;
regretInsertion.setScoringFunction(scorer);
regret = regretInsertion;
}
} else {
if(fastRegret) {
RegretInsertionFast regretInsertion = (RegretInsertionFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
RegretInsertionFast regretInsertion = (RegretInsertionFast) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setFastRegret(true)
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build();
scorer = getRegretScorer(vrp);
scorer = regretScorer;
regretInsertion.setScoringFunction(scorer);
regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes());
regret = regretInsertion;
}
else{
RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build();
scorer = getRegretScorer(vrp);
scorer = regretScorer;
regretInsertion.setScoringFunction(scorer);
regret = regretInsertion;
}
@ -510,7 +581,7 @@ public class Jsprit {
AbstractInsertionStrategy best;
if (vrp.getJobs().size() < 250 || es == null) {
BestInsertion bestInsertion = (BestInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
BestInsertion bestInsertion = (BestInsertion) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.BEST)
.considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
@ -518,7 +589,7 @@ public class Jsprit {
.build();
best = bestInsertion;
} else {
BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.BEST)
.considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
@ -532,6 +603,9 @@ public class Jsprit {
IterationStartsListener schrimpfThreshold = null;
if(acceptor == null) {
final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1, toDouble(getProperty(Parameter.THRESHOLD_ALPHA.toString())));
if (properties.containsKey(Parameter.THRESHOLD_INI_ABS.toString())) {
schrimpfAcceptance.setInitialThreshold(Double.valueOf(properties.getProperty(Parameter.THRESHOLD_INI_ABS.toString())));
} else {
schrimpfThreshold = new IterationStartsListener() {
@Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
@ -541,6 +615,7 @@ public class Jsprit {
}
}
};
}
acceptor = schrimpfAcceptance;
}
@ -569,8 +644,13 @@ public class Jsprit {
final SearchStrategy clusters_best = new SearchStrategy(Strategy.CLUSTER_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
clusters_best.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_BEST.toString(), best, clusters));
SearchStrategy stringRegret = new SearchStrategy(Strategy.STRING_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction);
stringRegret.addModule(new RuinAndRecreateModule(Strategy.STRING_REGRET.toString(), regret, stringRuin));
PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fm, stateManager, constraintManager);
SearchStrategy stringBest = new SearchStrategy(Strategy.STRING_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
stringBest.addModule(new RuinAndRecreateModule(Strategy.STRING_BEST.toString(), best, stringRuin));
PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, vehicleFleetManager, stateManager, constraintManager);
prettyBuilder.setRandom(random);
if (addCoreConstraints) {
prettyBuilder.addCoreStateAndConstraintStuff();
@ -582,7 +662,14 @@ public class Jsprit {
.withStrategy(worst_best, toDouble(getProperty(Strategy.WORST_BEST.toString())))
.withStrategy(worst_regret, toDouble(getProperty(Strategy.WORST_REGRET.toString())))
.withStrategy(clusters_regret, toDouble(getProperty(Strategy.CLUSTER_REGRET.toString())))
.withStrategy(clusters_best, toDouble(getProperty(Strategy.CLUSTER_BEST.toString())));
.withStrategy(clusters_best, toDouble(getProperty(Strategy.CLUSTER_BEST.toString())))
.withStrategy(stringBest, toDouble(getProperty(Strategy.STRING_BEST.toString())))
.withStrategy(stringRegret, toDouble(getProperty(Strategy.STRING_REGRET.toString())));
for (SearchStrategy customStrategy : customStrategies.keySet()) {
prettyBuilder.withStrategy(customStrategy, customStrategies.get(customStrategy));
}
if (getProperty(Parameter.CONSTRUCTION.toString()).equals(Construction.BEST_INSERTION.toString())) {
prettyBuilder.constructInitialSolutionWith(best, objectiveFunction);
} else {
@ -598,6 +685,7 @@ public class Jsprit {
vra.addListener(noiseConfigurator);
vra.addListener(noise);
vra.addListener(clusters);
if (increasingAbsoluteFixedCosts != null) vra.addListener(increasingAbsoluteFixedCosts);
if(toBoolean(getProperty(Parameter.BREAK_SCHEDULING.toString()))) {
vra.addListener(new BreakScheduling(vrp, stateManager, constraintManager));
@ -619,25 +707,36 @@ public class Jsprit {
private void handleExecutorShutdown(VehicleRoutingAlgorithm vra) {
if (setupExecutorInternally) {
final Thread hook = new Thread() {
public void run() {
if (!es.isShutdown()) {
System.err.println("shutdownHook shuts down executorService");
es.shutdown();
}
}
};
Runtime.getRuntime().addShutdownHook(hook);
vra.addListener(new AlgorithmEndsListener() {
@Override
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
es.shutdown();
Runtime.getRuntime().removeShutdownHook(hook);
}
});
}
if (es != null) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
if (!es.isShutdown()) {
System.err.println("shutdowHook shuts down executorService");
es.shutdown();
}
}
});
}
// if (es != null) {
//
// Runtime.getRuntime().addShutdownHook(hook);
// vra.addListener(new AlgorithmEndsListener() {
// @Override
// public void informAlgorithmEnds(VehicleRoutingProblem aProblem,
// Collection<VehicleRoutingProblemSolution> aSolutions) {
// Runtime.getRuntime().removeShutdownHook(hook);
// }
// });
// }
}
String getProperty(String key) {
@ -685,7 +784,7 @@ public class Jsprit {
}
}
for(Job j : solution.getUnassignedJobs()){
costs += maxCosts * 2 * (4 - j.getPriority());
costs += maxCosts * 2 * (11 - j.getPriority());
}
return costs;
}

View file

@ -0,0 +1,95 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint;
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
import com.graphhopper.jsprit.core.problem.constraint.HardRouteConstraint;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Created by schroeder on 06/02/17.
*/
abstract class AbstractInsertionCalculator implements JobInsertionCostsCalculator {
InsertionData checkRouteContraints(JobInsertionContext insertionContext, ConstraintManager constraintManager) {
for (HardRouteConstraint hardRouteConstraint : constraintManager.getHardRouteConstraints()) {
if (!hardRouteConstraint.fulfilled(insertionContext)) {
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
emptyInsertionData.addFailedConstrainName(hardRouteConstraint.getClass().getSimpleName());
return emptyInsertionData;
}
}
return null;
}
ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime, Collection<String> failedActivityConstraints, ConstraintManager constraintManager) {
ConstraintsStatus notFulfilled = null;
List<String> failed = new ArrayList<>();
for (HardActivityConstraint c : constraintManager.getCriticalHardActivityConstraints()) {
ConstraintsStatus status = c.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
failedActivityConstraints.add(c.getClass().getSimpleName());
return status;
} else {
if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
failed.add(c.getClass().getSimpleName());
notFulfilled = status;
}
}
}
if (notFulfilled != null) {
failedActivityConstraints.addAll(failed);
return notFulfilled;
}
for (HardActivityConstraint c : constraintManager.getHighPrioHardActivityConstraints()) {
ConstraintsStatus status = c.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
failedActivityConstraints.add(c.getClass().getSimpleName());
return status;
} else {
if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
failed.add(c.getClass().getSimpleName());
notFulfilled = status;
}
}
}
if (notFulfilled != null) {
failedActivityConstraints.addAll(failed);
return notFulfilled;
}
for (HardActivityConstraint constraint : constraintManager.getLowPrioHardActivityConstraints()) {
ConstraintsStatus status = constraint.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK) || status.equals(ConstraintsStatus.NOT_FULFILLED)) {
failedActivityConstraints.add(constraint.getClass().getSimpleName());
return status;
}
}
return ConstraintsStatus.FULFILLED;
}
}

View file

@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public abstract class AbstractInsertionStrategy implements InsertionStrategy {
@ -92,6 +93,10 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy {
return badJobs;
}
public void markUnassigned(Job unassigned, List<String> reasons) {
insertionsListeners.informJobUnassignedListeners(unassigned, reasons);
}
public abstract Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
@Override

View file

@ -0,0 +1,35 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.job.Job;
import java.util.Comparator;
/**
* Created by schroeder on 30/06/17.
*/
class AccordingToPriorities implements Comparator<Job> {
@Override
public int compare(Job o1, Job o2) {
return o1.getPriority() - o2.getPriority();
}
}

View file

@ -24,7 +24,10 @@ import com.graphhopper.jsprit.core.util.NoiseMaker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
@ -63,13 +66,15 @@ public final class BestInsertion extends AbstractInsertionStrategy {
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
Collections.shuffle(unassignedJobList, random);
sometimesSortPriorities(unassignedJobList);
Collections.sort(unassignedJobList, new AccordingToPriorities());
for (Job unassignedJob : unassignedJobList) {
Insertion bestInsertion = null;
InsertionData empty = new InsertionData.NoInsertionFound();
double bestInsertionCost = Double.MAX_VALUE;
for (VehicleRoute vehicleRoute : vehicleRoutes) {
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
if (iData instanceof InsertionData.NoInsertionFound) {
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
continue;
}
if (iData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()) {
@ -84,23 +89,16 @@ public final class BestInsertion extends AbstractInsertionStrategy {
bestInsertion = new Insertion(newRoute, newIData);
vehicleRoutes.add(newRoute);
}
} else {
empty.getFailedConstraintNames().addAll(newIData.getFailedConstraintNames());
}
if (bestInsertion == null) {
badJobs.add(unassignedJob);
markUnassigned(unassignedJob, empty.getFailedConstraintNames());
}
if (bestInsertion == null) badJobs.add(unassignedJob);
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
// nextInsertion();
}
return badJobs;
}
private void sometimesSortPriorities(List<Job> unassignedJobList) {
if(random.nextDouble() < 0.5){
Collections.sort(unassignedJobList, new Comparator<Job>() {
@Override
public int compare(Job o1, Job o2) {
return o1.getPriority() - o2.getPriority();
}
});
}
}
}

View file

@ -27,7 +27,10 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
@ -99,8 +102,9 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
Collections.shuffle(unassignedJobList, random);
sometimesSortPriorities(unassignedJobList);
Collections.sort(unassignedJobList, new AccordingToPriorities());
List<Batch> batches = distributeRoutes(vehicleRoutes, nuOfBatches);
List<String> failedConstraintNames = new ArrayList<>();
for (final Job unassignedJob : unassignedJobList) {
Insertion bestInsertion = null;
double bestInsertionCost = Double.MAX_VALUE;
@ -118,7 +122,10 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
for (int i = 0; i < batches.size(); i++) {
Future<Insertion> futureIData = completionService.take();
Insertion insertion = futureIData.get();
if (insertion == null) continue;
if (insertion.insertionData instanceof NoInsertionFound) {
failedConstraintNames.addAll(insertion.getInsertionData().getFailedConstraintNames());
continue;
}
if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) {
bestInsertion = insertion;
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
@ -136,29 +143,24 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
vehicleRoutes.add(newRoute);
batches.get(random.nextInt(batches.size())).routes.add(newRoute);
}
if (bestInsertion == null) badJobs.add(unassignedJob);
if (bestInsertion == null) {
badJobs.add(unassignedJob);
markUnassigned(unassignedJob, failedConstraintNames);
}
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
}
return badJobs;
}
private void sometimesSortPriorities(List<Job> unassignedJobList) {
if(random.nextDouble() < 0.5){
Collections.sort(unassignedJobList, new Comparator<Job>() {
@Override
public int compare(Job o1, Job o2) {
return o1.getPriority() - o2.getPriority();
}
});
}
}
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
Insertion bestInsertion = null;
InsertionData empty = new InsertionData.NoInsertionFound();
double bestInsertionCost = Double.MAX_VALUE;
for (VehicleRoute vehicleRoute : batch.routes) {
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
if (iData instanceof NoInsertionFound) {
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
continue;
}
if (iData.getInsertionCost() < bestInsertionCost) {
@ -166,6 +168,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
bestInsertionCost = iData.getInsertionCost();
}
}
if (bestInsertion == null) return new Insertion(null, empty);
return bestInsertion;
}

View file

@ -32,7 +32,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Random;
@Deprecated
class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsCalculator {

View file

@ -27,7 +27,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
@Deprecated
class CalculatesServiceInsertionWithTimeSchedulingInSlices implements JobInsertionCostsCalculator {

View file

@ -0,0 +1,77 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.state.InternalStates;
import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class DecreasingRelativeFixedCosts extends SolutionCompletenessRatio implements SoftRouteConstraint {
private static final Logger logger = LoggerFactory.getLogger(DecreasingRelativeFixedCosts.class);
private double weightDeltaFixCost = 0.5;
private RouteAndActivityStateGetter stateGetter;
public DecreasingRelativeFixedCosts(RouteAndActivityStateGetter stateGetter, int noJobs) {
super(noJobs);
this.stateGetter = stateGetter;
logger.debug("initialise {}", this);
}
public void setWeightOfFixCost(double weight) {
weightDeltaFixCost = weight;
logger.debug("set weightOfFixCostSaving to {}", weight);
}
@Override
public String toString() {
return "[name=DecreasingRelativeFixedCosts][weightOfFixedCostSavings=" + weightDeltaFixCost + "]";
}
private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) {
Capacity maxLoad = stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class);
if (maxLoad == null) maxLoad = Capacity.Builder.newInstance().build();
return maxLoad;
}
@Override
public double getCosts(JobInsertionContext insertionContext) {
VehicleRoute route = insertionContext.getRoute();
Capacity currentLoad = getCurrentMaxLoadInRoute(route);
Capacity load = Capacity.addup(currentLoad, insertionContext.getJob().getSize());
double currentRelFix = 0d;
if (route.getVehicle() != null && !(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
currentRelFix = route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions());
}
double newRelFix = insertionContext.getNewVehicle().getType().getVehicleCostParams().fix * (Capacity.divide(load, insertionContext.getNewVehicle().getType().getCapacityDimensions()));
double decreasingRelativeFixedCosts = (1 - solutionCompletenessRatio) * (newRelFix - currentRelFix);
return weightDeltaFixCost * solutionCompletenessRatio * decreasingRelativeFixedCosts;
}
}

View file

@ -31,14 +31,14 @@ public class DellAmicoFixCostCalculator implements SoftRouteConstraint, Insertio
private int nuOfJobsToRecreate;
private final JobInsertionConsideringFixCostsCalculator calculator;
private final IncreasingAbsoluteFixedCosts calculator;
private final int nuOfJobs;
public DellAmicoFixCostCalculator(final int nuOfJobs, final RouteAndActivityStateGetter stateGetter) {
super();
this.nuOfJobs = nuOfJobs;
calculator = new JobInsertionConsideringFixCostsCalculator(null, stateGetter);
calculator = new IncreasingAbsoluteFixedCosts(nuOfJobs);
}
@Override

View file

@ -0,0 +1,61 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class IncreasingAbsoluteFixedCosts extends SolutionCompletenessRatio implements SoftRouteConstraint {
private static final Logger logger = LoggerFactory.getLogger(IncreasingAbsoluteFixedCosts.class);
private double weightDeltaFixCost = 0.5;
public IncreasingAbsoluteFixedCosts(int noJobs) {
super(noJobs);
logger.debug("initialise {}", this);
}
public void setWeightOfFixCost(double weight) {
weightDeltaFixCost = weight;
logger.debug("set weightOfFixCostSaving to {}", weight);
}
@Override
public String toString() {
return "[name=IncreasingAbsoluteFixedCosts][weightOfFixedCostSavings=" + weightDeltaFixCost + "]";
}
@Override
public double getCosts(JobInsertionContext insertionContext) {
final VehicleRoute currentRoute = insertionContext.getRoute();
double currentFix = 0d;
if (currentRoute.getVehicle() != null && !(currentRoute.getVehicle() instanceof VehicleImpl.NoVehicle)) {
currentFix = currentRoute.getVehicle().getType().getVehicleCostParams().fix;
}
double increasingAbsoluteFixedCosts = solutionCompletenessRatio * (insertionContext.getNewVehicle().getType().getVehicleCostParams().fix - currentFix);
return weightDeltaFixCost * solutionCompletenessRatio * increasingAbsoluteFixedCosts;
}
}

View file

@ -31,6 +31,7 @@ import java.util.List;
*/
public class InsertionData {
public static class NoInsertionFound extends InsertionData {
public NoInsertionFound() {
@ -75,6 +76,8 @@ public class InsertionData {
return events;
}
private List<String> reasons = new ArrayList<>();
/**
* @return the additionalTime
*/
@ -82,6 +85,14 @@ public class InsertionData {
return additionalTime;
}
public void addFailedConstrainName(String name) {
reasons.add(name);
}
public List<String> getFailedConstraintNames() {
return reasons;
}
/**
* @param additionalTime the additionalTime to set
*/

View file

@ -33,7 +33,7 @@ class InsertionDataUpdater {
static boolean update(boolean addAllAvailable, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, TreeSet<VersionedInsertionData> insertionDataSet, int updateRound, Job unassignedJob, Collection<VehicleRoute> routes) {
for(VehicleRoute route : routes) {
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
Collection<Vehicle> relevantVehicles = new ArrayList<>();
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
relevantVehicles.add(route.getVehicle());
if(addAllAvailable && !initialVehicleIds.contains(route.getVehicle().getId())){
@ -71,7 +71,7 @@ class InsertionDataUpdater {
};
}
static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<Job> badJobs) {
static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<ScoredJob> badJobs) {
ScoredJob bestScoredJob = null;
for(Job j : unassignedJobList){
VehicleRoute bestRoute = null;
@ -79,6 +79,7 @@ class InsertionDataUpdater {
InsertionData secondBest = null;
TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[j.getIndex()];
Iterator<VersionedInsertionData> iterator = priorityQueue.iterator();
List<String> failedConstraintNames = new ArrayList<>();
while(iterator.hasNext()){
VersionedInsertionData versionedIData = iterator.next();
if(bestRoute != null){
@ -86,7 +87,10 @@ class InsertionDataUpdater {
continue;
}
}
if(versionedIData.getiData() instanceof InsertionData.NoInsertionFound) continue;
if (versionedIData.getiData() instanceof InsertionData.NoInsertionFound) {
failedConstraintNames.addAll(versionedIData.getiData().getFailedConstraintNames());
continue;
}
if(!(versionedIData.getRoute().getVehicle() instanceof VehicleImpl.NoVehicle)) {
if (versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) {
if (!switchAllowed) continue;
@ -136,9 +140,9 @@ class InsertionDataUpdater {
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
secondBest = iData;
}
}
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
if (best == null) {
badJobs.add(j);
badJobs.add(new ScoredJob.BadJob(j, failedConstraintNames));
continue;
}
double score = score(j, best, secondBest, scoringFunction);

View file

@ -1,135 +0,0 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.state.InternalStates;
import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
import com.graphhopper.jsprit.core.problem.driver.Driver;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCostsCalculator, SoftRouteConstraint {
private static final Logger logger = LoggerFactory.getLogger(JobInsertionConsideringFixCostsCalculator.class);
private final JobInsertionCostsCalculator standardServiceInsertion;
private double weight_deltaFixCost = 0.5;
private double solution_completeness_ratio = 0.5;
private RouteAndActivityStateGetter stateGetter;
public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardInsertionCalculator, RouteAndActivityStateGetter stateGetter) {
super();
this.standardServiceInsertion = standardInsertionCalculator;
this.stateGetter = stateGetter;
logger.debug("inialise {}", this);
}
@Override
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownPrice) {
double fixcost_contribution = getFixCostContribution(currentRoute, jobToInsert, newVehicle);
if (fixcost_contribution > bestKnownPrice) {
return InsertionData.createEmptyInsertionData();
}
InsertionData iData = standardServiceInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice);
if (iData instanceof InsertionData.NoInsertionFound) {
return iData;
}
double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution;
InsertionData insertionData = new InsertionData(totalInsertionCost, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), newVehicle, newDriver);
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
insertionData.getEvents().addAll(iData.getEvents());
return insertionData;
}
private double getFixCostContribution(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle) {
Capacity currentMaxLoadInRoute = getCurrentMaxLoadInRoute(currentRoute);
double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert,currentMaxLoadInRoute);
double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert,currentMaxLoadInRoute);
double deltaFixCost = (1 - solution_completeness_ratio) * relFixCost + solution_completeness_ratio * absFixCost;
double fixcost_contribution = weight_deltaFixCost * solution_completeness_ratio * deltaFixCost;
return fixcost_contribution;
}
public void setWeightOfFixCost(double weight) {
weight_deltaFixCost = weight;
logger.debug("set weightOfFixCostSaving to {}", weight);
}
@Override
public String toString() {
return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weight_deltaFixCost + "]";
}
public void setSolutionCompletenessRatio(double ratio) {
solution_completeness_ratio = ratio;
}
public double getSolutionCompletenessRatio() { return solution_completeness_ratio; }
private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job, Capacity currentMaxLoadInRoute) {
Capacity load = Capacity.addup(currentMaxLoadInRoute, job.getSize());
double currentFix = 0.0;
if (route.getVehicle() != null) {
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
currentFix += route.getVehicle().getType().getVehicleCostParams().fix;
}
}
if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) {
return Double.MAX_VALUE;
}
return newVehicle.getType().getVehicleCostParams().fix - currentFix;
}
private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job, Capacity currentLoad) {
Capacity load = Capacity.addup(currentLoad, job.getSize());
double currentRelFix = 0.0;
if (route.getVehicle() != null) {
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
currentRelFix += route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions());
}
}
if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) {
return Double.MAX_VALUE;
}
double relativeFixCost = newVehicle.getType().getVehicleCostParams().fix * (Capacity.divide(load, newVehicle.getType().getCapacityDimensions())) - currentRelFix;
return relativeFixCost;
}
private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) {
Capacity maxLoad = stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class);
if (maxLoad == null) maxLoad = Capacity.Builder.newInstance().build();
return maxLoad;
}
@Override
public double getCosts(JobInsertionContext insertionContext) {
return getFixCostContribution(insertionContext.getRoute(), insertionContext.getJob(), insertionContext.getNewVehicle());
}
}

View file

@ -218,10 +218,10 @@ public class JobInsertionCostsCalculatorBuilder {
addAlgorithmListeners(standardLocal.getAlgorithmListener());
addInsertionListeners(standardLocal.getInsertionListener());
if (considerFixedCost) {
CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost);
baseCalculator = withFixed.getCalculator();
addAlgorithmListeners(withFixed.getAlgorithmListener());
addInsertionListeners(withFixed.getInsertionListener());
// CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost);
// baseCalculator = withFixed.getCalculator();
// addAlgorithmListeners(withFixed.getAlgorithmListener());
// addInsertionListeners(withFixed.getInsertionListener());
}
if (timeScheduling) {
// baseCalculator = new CalculatesServiceInsertionWithTimeSchedulingInSlices(baseCalculator,timeSlice,neighbors);
@ -309,14 +309,6 @@ public class JobInsertionCostsCalculatorBuilder {
return calculatorPlusListeners;
}
private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCostsCalculator baseCalculator, RouteAndActivityStateGetter activityStates2, double weightOfFixedCosts) {
final JobInsertionConsideringFixCostsCalculator withFixCost = new JobInsertionConsideringFixCostsCalculator(baseCalculator, activityStates2);
withFixCost.setWeightOfFixCost(weightOfFixedCosts);
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost);
calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost));
return calcPlusListeners;
}
private CalculatorPlusListeners createStandardRoute(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter activityStates2, int forwardLooking, int solutionMemory) {
ActivityInsertionCostsCalculator routeLevelCostEstimator;
if (activityInsertionCostCalculator == null && addDefaultCostCalc) {

View file

@ -22,6 +22,7 @@ import com.graphhopper.jsprit.core.algorithm.state.InternalStates;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment;
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
@ -77,7 +78,9 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
double oldCosts = 0.;
if (iFacts.getRoute().isEmpty()) {
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
double tp_costs_prevAct_nextAct = 0.;
if (newAct instanceof DeliverShipment)
tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
oldCosts += tp_costs_prevAct_nextAct;
} else {
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());

View file

@ -105,10 +105,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
}
}
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
List<Job> jobs = new ArrayList<>(unassignedJobs);
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>();
List<Job> unassignedJobList = new ArrayList<>(jobs);
List<ScoredJob> badJobList = new ArrayList<>();
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
if (bestScoredJob != null) {
if (bestScoredJob.isNewRoute()) {
@ -117,9 +117,11 @@ public class RegretInsertion extends AbstractInsertionStrategy {
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
jobs.remove(bestScoredJob.getJob());
}
for (Job bad : badJobList) {
jobs.remove(bad);
badJobs.add(bad);
for (ScoredJob bad : badJobList) {
Job unassigned = bad.getJob();
jobs.remove(unassigned);
badJobs.add(unassigned);
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
}
}
return badJobs;
@ -132,12 +134,12 @@ public class RegretInsertion extends AbstractInsertionStrategy {
return null;
}
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<Job> badJobs) {
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<ScoredJob> badJobs) {
ScoredJob bestScoredJob = null;
for (Job unassignedJob : unassignedJobList) {
ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
if (scoredJob instanceof ScoredJob.BadJob) {
badJobs.add(unassignedJob);
badJobs.add(scoredJob);
continue;
}
if (bestScoredJob == null) bestScoredJob = scoredJob;
@ -158,14 +160,17 @@ public class RegretInsertion extends AbstractInsertionStrategy {
InsertionData best = null;
InsertionData secondBest = null;
VehicleRoute bestRoute = null;
List<String> failedConstraintNames = new ArrayList<>();
double benchmark = Double.MAX_VALUE;
for (VehicleRoute route : routes) {
if (secondBest != null) {
benchmark = secondBest.getInsertionCost();
}
InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark);
if (iData instanceof InsertionData.NoInsertionFound) continue;
if (iData instanceof InsertionData.NoInsertionFound) {
failedConstraintNames.addAll(iData.getFailedConstraintNames());
continue;
}
if (best == null) {
best = iData;
bestRoute = route;
@ -191,9 +196,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
secondBest = iData;
}
}
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
if (best == null) {
return new ScoredJob.BadJob(unassignedJob);
ScoredJob.BadJob badJob = new ScoredJob.BadJob(unassignedJob, failedConstraintNames);
return badJob;
}
double score = score(unassignedJob, best, secondBest, scoringFunction);
ScoredJob scoredJob;

View file

@ -109,10 +109,10 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
}
}
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
List<Job> jobs = new ArrayList<>(unassignedJobs);
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>();
List<Job> unassignedJobList = new ArrayList<>(jobs);
List<ScoredJob> badJobList = new ArrayList<>();
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
if (bestScoredJob != null) {
if (bestScoredJob.isNewRoute()) {
@ -121,15 +121,17 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
jobs.remove(bestScoredJob.getJob());
}
for (Job j : badJobList) {
jobs.remove(j);
badJobs.add(j);
for (ScoredJob bad : badJobList) {
Job unassigned = bad.getJob();
jobs.remove(unassigned);
badJobs.add(unassigned);
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
}
}
return badJobs;
}
private ScoredJob nextJob(final Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<Job> badJobList) {
private ScoredJob nextJob(final Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<ScoredJob> badJobList) {
ScoredJob bestScoredJob = null;
for (final Job unassignedJob : unassignedJobList) {
@ -148,7 +150,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
Future<ScoredJob> fsj = completionService.take();
ScoredJob sJob = fsj.get();
if (sJob instanceof ScoredJob.BadJob) {
badJobList.add(sJob.getJob());
badJobList.add(sJob);
continue;
}
if (bestScoredJob == null) {

View file

@ -143,8 +143,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
int updateRound = 0;
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>();
List<Job> unassignedJobList = new ArrayList<>(jobs);
List<ScoredJob> badJobList = new ArrayList<>();
if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound,firstRun,lastModified,updates);
if(firstRun) firstRun = false;
@ -159,9 +159,11 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
lastModified = bestScoredJob.getRoute();
}
else lastModified = null;
for (Job bad : badJobList) {
jobs.remove(bad);
badJobs.add(bad);
for (ScoredJob bad : badJobList) {
Job unassigned = bad.getJob();
jobs.remove(unassigned);
badJobs.add(unassigned);
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
}
}
return badJobs;
@ -172,7 +174,7 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
boolean updatedAllRoutes = false;
for (final Job unassignedJob : unassignedJobList) {
if(priorityQueues[unassignedJob.getIndex()] == null){
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
}
if(firstRun) {
updatedAllRoutes = true;

View file

@ -131,10 +131,10 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
VehicleRoute lastModified = null;
boolean firstRun = true;
int updateRound = 0;
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
Map<VehicleRoute, Integer> updates = new HashMap<>();
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>();
List<Job> unassignedJobList = new ArrayList<>(jobs);
List<ScoredJob> badJobList = new ArrayList<>();
if(!firstRun && lastModified == null) throw new IllegalStateException("last modified route is null. this should not be.");
if(firstRun){
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates);
@ -156,9 +156,11 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
lastModified = bestScoredJob.getRoute();
}
else lastModified = null;
for (Job bad : badJobList) {
jobs.remove(bad);
badJobs.add(bad);
for (ScoredJob bad : badJobList) {
Job unassigned = bad.getJob();
jobs.remove(unassigned);
badJobs.add(unassigned);
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
}
}
return badJobs;
@ -167,7 +169,7 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
private void updateInsertionData(TreeSet<VersionedInsertionData>[] priorityQueues, Collection<VehicleRoute> routes, List<Job> unassignedJobList, int updateRound, boolean firstRun, VehicleRoute lastModified, Map<VehicleRoute, Integer> updates) {
for (Job unassignedJob : unassignedJobList) {
if(priorityQueues[unassignedJob.getIndex()] == null){
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
}
if(firstRun) {
InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes);

View file

@ -31,7 +31,7 @@ import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivity
import java.util.ArrayList;
import java.util.List;
@Deprecated
class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCostsCalculator {
private VehicleRoutingActivityCosts activityCosts;

View file

@ -21,6 +21,8 @@ package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import java.util.List;
/**
* Created by schroeder on 15/10/15.
*/
@ -28,8 +30,14 @@ class ScoredJob {
static class BadJob extends ScoredJob {
BadJob(Job job) {
super(job, 0., null, null, false);
BadJob(Job job, List<String> failedConstraintNames) {
super(job, 0., getEmptyInsertion(failedConstraintNames), null, false);
}
private static InsertionData getEmptyInsertion(List<String> failedConstraintNames) {
InsertionData empty = new InsertionData.NoInsertionFound();
empty.getFailedConstraintNames().addAll(failedConstraintNames);
return empty;
}
}

View file

@ -33,9 +33,9 @@ class Scorer {
if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob
//if only one vehicle, I want the job to be inserted with min iCosts
//if there are more vehicles, I want this job to be prioritized since there are no alternatives
score = (4 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
score = (11 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
} else {
score = (4 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
score = (11 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
}
return score;
}

View file

@ -25,6 +25,6 @@ import com.graphhopper.jsprit.core.problem.job.Job;
*/
public interface ScoringFunction {
public double score(InsertionData best, Job job);
double score(InsertionData best, Job job);
}

View file

@ -18,8 +18,10 @@
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.constraint.*;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
import com.graphhopper.jsprit.core.problem.constraint.SoftActivityConstraint;
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import com.graphhopper.jsprit.core.problem.driver.Driver;
@ -36,6 +38,8 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
@ -43,13 +47,13 @@ import java.util.Iterator;
*
* @author schroeder
*/
final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
private static final Logger logger = LoggerFactory.getLogger(ServiceInsertionCalculator.class);
private HardRouteConstraint hardRouteLevelConstraint;
// private HardRouteConstraint hardRouteLevelConstraint;
private HardActivityConstraint hardActivityLevelConstraint;
// private HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint;
@ -65,12 +69,13 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
private ConstraintManager constraintManager;
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
super();
this.transportCosts = routingCosts;
this.activityCosts = activityCosts;
hardRouteLevelConstraint = constraintManager;
hardActivityLevelConstraint = constraintManager;
this.constraintManager = constraintManager;
softActivityConstraint = constraintManager;
softRouteConstraint = constraintManager;
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
@ -103,9 +108,10 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
/*
check hard constraints at route level
*/
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
return InsertionData.createEmptyInsertionData();
}
InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager);
if (noInsertion != null) return noInsertion;
Collection<String> failedActivityConstraints = new ArrayList<>();
/*
check soft constraints at route level
@ -142,7 +148,7 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
ActivityContext activityContext = new ActivityContext();
activityContext.setInsertionIndex(actIndex);
insertionContext.setActivityContext(activityContext);
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
ConstraintsStatus status = fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime, failedActivityConstraints, constraintManager);
if (status.equals(ConstraintsStatus.FULFILLED)) {
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
@ -163,7 +169,9 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
actIndex++;
}
if(insertionIndex == InsertionData.NO_INDEX) {
return InsertionData.createEmptyInsertionData();
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
emptyInsertionData.getFailedConstraintNames().addAll(failedActivityConstraints);
return emptyInsertionData;
}
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(bestTimeWindow.getStart());
@ -173,4 +181,6 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
return insertionData;
}
}

View file

@ -45,7 +45,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
@Deprecated
final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsCalculator {
private static final Logger logger = LoggerFactory.getLogger(ServiceInsertionOnRouteLevelCalculator.class);

View file

@ -18,8 +18,10 @@
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.constraint.*;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
import com.graphhopper.jsprit.core.problem.constraint.SoftActivityConstraint;
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import com.graphhopper.jsprit.core.problem.driver.Driver;
@ -36,16 +38,19 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
final class ShipmentInsertionCalculator extends AbstractInsertionCalculator {
private static final Logger logger = LoggerFactory.getLogger(ShipmentInsertionCalculator.class);
private HardRouteConstraint hardRouteLevelConstraint;
private final ConstraintManager constraintManager;
private HardActivityConstraint hardActivityLevelConstraint;
// private HardRouteConstraint hardRouteLevelConstraint;
//
// private HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint;
@ -64,8 +69,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager) {
super();
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
this.hardRouteLevelConstraint = constraintManager;
this.hardActivityLevelConstraint = constraintManager;
this.constraintManager = constraintManager;
this.softActivityConstraint = constraintManager;
this.softRouteConstraint = constraintManager;
this.transportCosts = routingCosts;
@ -99,9 +103,8 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
/*
check hard route constraints
*/
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
return InsertionData.createEmptyInsertionData();
}
InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager);
if (noInsertion != null) return noInsertion;
/*
check soft route constraints
*/
@ -132,6 +135,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
//pickupShipmentLoop
List<TourActivity> activities = currentRoute.getTourActivities().getActivities();
List<String> failedActivityConstraints = new ArrayList<>();
while (!tourEnd) {
TourActivity nextAct;
if (i < activities.size()) {
@ -148,7 +152,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
ActivityContext activityContext = new ActivityContext();
activityContext.setInsertionIndex(i);
insertionContext.setActivityContext(activityContext);
ConstraintsStatus pickupShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime);
ConstraintsStatus pickupShipmentConstraintStatus = fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime, failedActivityConstraints, constraintManager);
if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED)) {
pickupInsertionNotFulfilledBreak = false;
continue;
@ -194,7 +198,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
ActivityContext activityContext_ = new ActivityContext();
activityContext_.setInsertionIndex(j);
insertionContext.setActivityContext(activityContext_);
ConstraintsStatus deliverShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
ConstraintsStatus deliverShipmentConstraintStatus = fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop, failedActivityConstraints, constraintManager);
if (deliverShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)) {
double additionalDeliveryICosts = softActivityConstraint.getCosts(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
double deliveryAIC = calculate(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
@ -230,7 +234,9 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
i++;
}
if (pickupInsertionIndex == InsertionData.NO_INDEX) {
return InsertionData.createEmptyInsertionData();
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
emptyInsertionData.getFailedConstraintNames().addAll(failedActivityConstraints);
return emptyInsertionData;
}
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
pickupShipment.setTheoreticalEarliestOperationStartTime(bestPickupTimeWindow.getStart());

View file

@ -15,50 +15,48 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.recreate;
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionStartsListener;
import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobInsertedListener;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import java.util.Collection;
/**
* Created by schroeder on 11/01/17.
*/
class SolutionCompletenessRatio implements InsertionStartsListener, JobInsertedListener {
final class ConfigureFixCostCalculator implements InsertionStartsListener, JobInsertedListener {
protected double solutionCompletenessRatio = 0.5;
private final VehicleRoutingProblem vrp;
private final JobInsertionConsideringFixCostsCalculator calcConsideringFix;
private final double minRatio = 0.5;
private final int nuOfJobs;
private int nuOfJobsToRecreate;
public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, JobInsertionConsideringFixCostsCalculator calcConsideringFix) {
super();
this.vrp = vrp;
this.calcConsideringFix = calcConsideringFix;
public SolutionCompletenessRatio(int nuOfJobs) {
this.nuOfJobs = nuOfJobs;
}
@Override
public String toString() {
return "[name=configureFixCostCalculator]";
public void setSolutionCompletenessRatio(double ratio) {
solutionCompletenessRatio = ratio;
}
public double getSolutionCompletenessRatio() {
return solutionCompletenessRatio;
}
@Override
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
this.nuOfJobsToRecreate = unassignedJobs.size();
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
calcConsideringFix.setSolutionCompletenessRatio(Math.max(minRatio,completenessRatio));
solutionCompletenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs));
}
@Override
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
nuOfJobsToRecreate--;
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
calcConsideringFix.setSolutionCompletenessRatio(Math.max(minRatio,completenessRatio));
solutionCompletenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs));
}
}

View file

@ -98,7 +98,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
}
Vehicle selectedVehicle = currentRoute.getVehicle();
Driver selectedDriver = currentRoute.getDriver();
InsertionData bestIData = InsertionData.createEmptyInsertionData();
InsertionData bestIData = new InsertionData.NoInsertionFound();
double bestKnownCost_ = bestKnownCost;
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
if (!(selectedVehicle instanceof VehicleImpl.NoVehicle)) {
@ -115,6 +115,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
else depTime = v.getEarliestDeparture();
InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
if (iData instanceof InsertionData.NoInsertionFound) {
bestIData.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
continue;
}
if (iData.getInsertionCost() < bestKnownCost_) {

View file

@ -24,6 +24,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class InsertionListeners {
@ -74,6 +75,14 @@ public class InsertionListeners {
}
}
public void informJobUnassignedListeners(Job unassigned, List<String> reasons) {
for (InsertionListener l : listeners) {
if (l instanceof JobUnassignedListener) {
((JobUnassignedListener) l).informJobUnassigned(unassigned, reasons);
}
}
}
public void addListener(InsertionListener insertionListener) {
listeners.add(insertionListener);
}

View file

@ -15,12 +15,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.analysis.util;
import com.graphhopper.jsprit.core.util.BenchmarkResult;
package com.graphhopper.jsprit.core.algorithm.recreate.listener;
import com.graphhopper.jsprit.core.problem.job.Job;
import java.util.Collection;
public interface BenchmarkWriter {
public void write(Collection<BenchmarkResult> results);
/**
* Created by schroeder on 06/02/17.
*/
public interface JobUnassignedListener extends InsertionListener {
void informJobUnassigned(Job unassigned, Collection<String> failedConstraintNames);
}

View file

@ -0,0 +1,218 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.ruin;
import com.graphhopper.jsprit.core.problem.AbstractActivity;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.util.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* RuinString is adopted from
* <p>
* Technical report 7.11.2016
* A Fresh Ruin & Recreate Implementation for the Capacitated Vehicle Routing Problem
* Jan Christiaens, Greet Vanden Berghe
* KU Leuven, Department of Computer Science, CODeS & iMinds-ITEC
* Gebr. De Smetstraat 1, 9000 Gent, Belgium, jan.christiaens@cs.kuleuven.be, greet.vandenberghe@cs.kuleuven.be
* <p>
* https://lirias.kuleuven.be/bitstream/123456789/556398/1/asb_rr_2016.pdf
*
* @author stefan
*/
public final class RuinString extends AbstractRuinStrategy {
private static Logger logger = LoggerFactory.getLogger(RuinString.class);
private final VehicleRoutingProblem vrp;
private final JobNeighborhoods jobNeighborhoods;
private int kMin = 1;
private int kMax = 6;
private int lMin = 30;
private int lMax = 60;
public RuinString(VehicleRoutingProblem vrp, JobNeighborhoods jobNeighborhoods) {
super(vrp);
this.vrp = vrp;
this.jobNeighborhoods = jobNeighborhoods;
logger.debug("initialise {}", this);
}
public void setNoRoutes(int kMin, int kMax) {
this.kMin = kMin;
this.kMax = kMax;
}
public void setStringLength(int lMin, int lMax) {
this.lMin = lMin;
this.lMax = lMax;
}
@Override
public String toString() {
return "[name=splitRuin]";
}
/**
* Ruins the collection of vehicleRoutes, i.e. removes a share of jobs. First, it selects a job randomly. Second, it identifies its neighborhood. And finally, it removes
* the neighborhood plus the randomly selected job from the number of vehicleRoutes. All removed jobs are then returned as a collection.
*/
@Override
public Collection<Job> ruinRoutes(Collection<VehicleRoute> vehicleRoutes) {
if (vehicleRoutes.isEmpty() || vrp.getJobs().isEmpty()) {
return Collections.emptyList();
}
int noStrings;
if (kMin == kMax) noStrings = kMax;
else noStrings = kMin + random.nextInt((kMax - kMin));
noStrings = Math.min(noStrings, vehicleRoutes.size());
Set<Job> unassignedJobs = new HashSet<>();
Set<VehicleRoute> ruinedRoutes = new HashSet<>();
Job prevJob = RandomUtils.nextJob(vrp.getJobs().values(), random);
Iterator<Job> neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(kMax * lMax, prevJob);
while (neighborhoodIterator.hasNext() && ruinedRoutes.size() <= noStrings) {
if (!unassignedJobs.contains(prevJob)) {
VehicleRoute route = getRouteOf(prevJob, vehicleRoutes);
if (route != null && !ruinedRoutes.contains(route)) {
if (random.nextDouble() < .5) {
ruinRouteWithStringRuin(route, prevJob, unassignedJobs);
} else {
ruinRouteWithSplitStringRuin(route, prevJob, unassignedJobs);
}
ruinedRoutes.add(route);
}
}
prevJob = neighborhoodIterator.next();
}
return unassignedJobs;
}
private VehicleRoute getRouteOf(Job job, Collection<VehicleRoute> vehicleRoutes) {
for (VehicleRoute route : vehicleRoutes) {
if (route.getTourActivities().servesJob(job)) return route;
}
return null;
}
private void ruinRouteWithSplitStringRuin(VehicleRoute seedRoute, Job prevJob, Set<Job> unassignedJobs) {
int noActivities = seedRoute.getActivities().size();
int stringLength;
if (lMin == lMax) stringLength = lMin;
else stringLength = lMin + random.nextInt(lMax - lMin);
stringLength = Math.min(stringLength, seedRoute.getActivities().size());
int preservedSubstringLength = StringUtil.determineSubstringLength(stringLength, noActivities, random);
List<AbstractActivity> acts = vrp.getActivities(prevJob);
AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random);
int seedIndex = 0;
int index = 0;
for (TourActivity act : seedRoute.getActivities()) {
if (act.getIndex() == randomSeedAct.getIndex()) {
seedIndex = index;
break;
}
index++;
}
int totalStringLength = stringLength + preservedSubstringLength;
List<Integer> stringBounds = StringUtil.getLowerBoundsOfAllStrings(totalStringLength, seedIndex, noActivities);
if (stringBounds.isEmpty()) return;
int lowerBound = RandomUtils.nextItem(stringBounds, random);
List<Job> jobs2Remove = new ArrayList<>();
int startIndexOfPreservedSubstring = random.nextInt(stringLength);
int position = 0;
int noStringsInPreservedSubstring = 0;
boolean isPreservedSubstring = false;
for (int i = lowerBound; i < (lowerBound + totalStringLength); i++) {
if (position == startIndexOfPreservedSubstring) {
isPreservedSubstring = true;
}
if (noStringsInPreservedSubstring >= preservedSubstringLength) {
isPreservedSubstring = false;
}
if (!isPreservedSubstring) {
TourActivity act = seedRoute.getActivities().get(i);
if (act instanceof TourActivity.JobActivity) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (vrp.getJobs().containsKey(job.getId())) {
jobs2Remove.add(job);
}
}
} else noStringsInPreservedSubstring++;
position++;
}
for (Job job : jobs2Remove) {
removeJob(job, seedRoute);
unassignedJobs.add(job);
}
}
private void ruinRouteWithStringRuin(VehicleRoute seedRoute, Job prevJob, Set<Job> unassignedJobs) {
int stringLength = lMin + random.nextInt(lMax - lMin);
stringLength = Math.min(stringLength, seedRoute.getActivities().size());
List<AbstractActivity> acts = vrp.getActivities(prevJob);
AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random);
int seedIndex = 0;
int noActivities = seedRoute.getActivities().size();
int index = 0;
for (TourActivity act : seedRoute.getActivities()) {
if (act.getIndex() == randomSeedAct.getIndex()) {
seedIndex = index;
break;
}
index++;
}
List<Integer> stringBounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
if (stringBounds.isEmpty()) return;
int lowerBound = RandomUtils.nextItem(stringBounds, random);
List<Job> jobs2Remove = new ArrayList<>();
for (int i = lowerBound; i < (lowerBound + stringLength); i++) {
TourActivity act = seedRoute.getActivities().get(i);
if (act instanceof TourActivity.JobActivity) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (vrp.getJobs().containsKey(job.getId())) {
jobs2Remove.add(job);
}
}
}
for (Job job : jobs2Remove) {
removeJob(job, seedRoute);
unassignedJobs.add(job);
}
}
}

View file

@ -0,0 +1,52 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.ruin;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by schroeder on 13/01/17.
*/
class StringUtil {
static List<Integer> getLowerBoundsOfAllStrings(int length, int seedIndex, int routeLength) {
List<Integer> lowerBounds = new ArrayList<>();
for (int i = 1; i <= length; i++) {
int lower = seedIndex - (length - i);
int upper = seedIndex + (i - 1);
if (lower >= 0 && upper < routeLength) {
lowerBounds.add(lower);
}
}
return lowerBounds;
}
static int determineSubstringLength(int baseLength, int routeLength, Random random) {
if (baseLength == routeLength) return 0;
int substringLength = 1;
while (baseLength + substringLength < routeLength) {
if (random.nextDouble() < 0.01) {
return substringLength;
} else substringLength++;
}
return substringLength;
}
}

View file

@ -0,0 +1,120 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.state;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.ActivityVisitor;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeKey;
import java.util.*;
/**
* Created by schroeder on 17/05/16.
*/
public class VehicleDependentTraveledDistance implements StateUpdater, ActivityVisitor {
static class State {
Location prevLocation;
double distance;
public State(Location prevLocation, double distance) {
this.prevLocation = prevLocation;
this.distance = distance;
}
public Location getPrevLocation() {
return prevLocation;
}
public double getDistance() {
return distance;
}
}
private final TransportDistance transportDistance;
private final StateManager stateManager;
private final StateId traveledDistanceId;
private VehicleRoute route;
private List<Vehicle> uniqueVehicles;
private Map<VehicleTypeKey,State> states;
public VehicleDependentTraveledDistance(TransportDistance transportCostMatrices, StateManager stateManager, StateId distanceInRouteId, Collection<Vehicle> vehicles) {
this.transportDistance = transportCostMatrices;
this.stateManager = stateManager;
this.traveledDistanceId = distanceInRouteId;
uniqueVehicles = getUniqueVehicles(vehicles);
}
private List<Vehicle> getUniqueVehicles(Collection<Vehicle> vehicles) {
Set<VehicleTypeKey> types = new HashSet<>();
List<Vehicle> uniqueVehicles = new ArrayList<>();
for(Vehicle v : vehicles){
if(!types.contains(v.getVehicleTypeIdentifier())){
types.add(v.getVehicleTypeIdentifier());
uniqueVehicles.add(v);
}
}
return uniqueVehicles;
}
@Override
public void begin(VehicleRoute route) {
this.route = route;
states = new HashMap<>();
for(Vehicle v : uniqueVehicles){
State state = new State(v.getStartLocation(),0);
states.put(v.getVehicleTypeIdentifier(),state);
}
}
@Override
public void visit(TourActivity activity) {
for(Vehicle v : uniqueVehicles){
State old = states.get(v.getVehicleTypeIdentifier());
double distance = old.getDistance();
distance += transportDistance.getDistance(old.getPrevLocation(),activity.getLocation(),0,v);
stateManager.putActivityState(activity,v,traveledDistanceId,distance);
states.put(v.getVehicleTypeIdentifier(),new State(activity.getLocation(),distance));
}
}
@Override
public void finish() {
for(Vehicle v : uniqueVehicles){
State old = states.get(v.getVehicleTypeIdentifier());
double distance = old.getDistance();
if(v.isReturnToDepot()) {
distance += transportDistance.getDistance(old.getPrevLocation(), v.getEndLocation(), 0, v);
}
stateManager.putRouteState(route,v,traveledDistanceId, distance);
}
}
}

View file

@ -30,7 +30,9 @@ import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
@ -119,9 +121,22 @@ public class VariationCoefficientTermination implements PrematureAlgorithmTermin
}
}
public void informIterationEnds(int i, VehicleRoutingProblem problem, VehicleRoutingProblemSolution solution) {
informIterationEnds(i, problem, toList(solution));
}
private List<VehicleRoutingProblemSolution> toList(VehicleRoutingProblemSolution solution) {
List<VehicleRoutingProblemSolution> solutions = new ArrayList<>();
solutions.add(solution);
return solutions;
}
@Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
if (lastAccepted == null) lastAccepted = Solutions.bestOf(solutions);
}
public void informIterationStarts(int i, VehicleRoutingProblem problem, VehicleRoutingProblemSolution solution) {
informIterationStarts(i, problem, toList(solution));
}
}

View file

@ -26,7 +26,9 @@ import com.graphhopper.jsprit.core.problem.job.Job;
public abstract class AbstractJob implements Job {
private int index;
private Object userData;
@Override
public int getIndex() {
return index;
}
@ -35,4 +37,15 @@ public abstract class AbstractJob implements Job {
this.index = index;
}
/**
* @return User-specific domain data associated by the job
*/
public Object getUserData() {
return userData;
}
protected void setUserData(Object userData) {
this.userData = userData;
}
}

View file

@ -30,6 +30,7 @@ public abstract class AbstractVehicle implements Vehicle {
private int index;
@Override
public int getIndex() {
return index;
}
@ -44,6 +45,21 @@ public abstract class AbstractVehicle implements Vehicle {
private VehicleTypeKey vehicleIdentifier;
private Object userData;
/**
* @return User-specific domain data associated with the vehicle
*/
@Override
public Object getUserData() {
return userData;
}
protected void setUserData(Object userData) {
this.userData = userData;
}
@Override
public int getIndex() {
return index;
}
@ -52,6 +68,7 @@ public abstract class AbstractVehicle implements Vehicle {
this.index = index;
}
@Override
public VehicleTypeKey getVehicleTypeIdentifier() {
return vehicleIdentifier;
}

View file

@ -64,26 +64,77 @@ public final class Location implements HasIndex, HasId {
private Coordinate coordinate;
private String name = "";
private Object userData;
public static Builder newInstance() {
return new Builder();
}
/**
* Sets user specific domain data associated with the object.
*
* <p>
* The user data is a black box for the framework, it only stores it,
* but never interacts with it in any way.
* </p>
*
* @param userData
* any object holding the domain specific user data
* associated with the object.
* @return builder
*/
public Builder setUserData(Object userData) {
this.userData = userData;
return this;
}
/**
* Sets location index
*
* @param index
* @return the builder
*/
public Builder setIndex(int index) {
if (index < 0) throw new IllegalArgumentException("index must be >= 0");
this.index = index;
return this;
}
/**
* Sets coordinate of location
*
* @param coordinate
* @return
*/
public Builder setCoordinate(Coordinate coordinate) {
this.coordinate = coordinate;
return this;
}
/**
* Sets location id
*
* @param id
* @return
*/
public Builder setId(String id) {
this.id = id;
return this;
}
/**
* Adds name, e.g. street name, to location
*
* @param name
* @return
*/
public Builder setName(String name){
this.name = name;
return this;
}
public Location build() {
if (id == null && coordinate == null) {
if (index == -1) throw new IllegalArgumentException("either id or coordinate or index must be set");
@ -107,10 +158,23 @@ public final class Location implements HasIndex, HasId {
private final String id;
private final String name;
private Object userData;
private Location(Builder builder) {
this.userData = builder.userData;
this.index = builder.index;
this.coordinate = builder.coordinate;
this.id = builder.id;
this.name = builder.name;
}
/**
* @return User-specific domain data associated by the job
*/
public Object getUserData() {
return userData;
}
@Override
@ -127,6 +191,8 @@ public final class Location implements HasIndex, HasId {
return coordinate;
}
public String getName() { return name; }
@Override
public boolean equals(Object o) {
if (this == o) return true;

View file

@ -568,8 +568,6 @@ public class VehicleRoutingProblem {
*/
private final FleetSize fleetSize;
private final Locations locations;
private Map<Job, List<AbstractActivity>> activityMap;
private int nuActivities;
@ -591,7 +589,6 @@ public class VehicleRoutingProblem {
this.initialVehicleRoutes = builder.initialRoutes;
this.transportCosts = builder.transportCosts;
this.activityCosts = builder.activityCosts;
this.locations = builder.getLocations();
this.activityMap = builder.activityMap;
this.nuActivities = builder.activityIndexCounter;
this.allLocations = builder.allLocations;

View file

@ -37,6 +37,7 @@ import java.util.List;
*/
public class ConstraintManager implements HardActivityConstraint, HardRouteConstraint, SoftActivityConstraint, SoftRouteConstraint {
public static enum Priority {
CRITICAL, HIGH, LOW
}
@ -45,7 +46,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
private HardActivityLevelConstraintManager actLevelConstraintManager = new HardActivityLevelConstraintManager();
private HardRouteLevelConstraintManager routeLevelConstraintManager = new HardRouteLevelConstraintManager();
private HardRouteLevelConstraintManager hardRouteConstraintManager = new HardRouteLevelConstraintManager();
private SoftActivityConstraintManager softActivityConstraintManager = new SoftActivityConstraintManager();
@ -76,6 +77,25 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
resolveConstraints(constraints);
}
public Collection<HardRouteConstraint> getHardRouteConstraints() {
return hardRouteConstraintManager.getConstraints();
}
public Collection<HardActivityConstraint> getCriticalHardActivityConstraints() {
return actLevelConstraintManager.getCriticalConstraints();
}
public Collection<HardActivityConstraint> getHighPrioHardActivityConstraints() {
return actLevelConstraintManager.getHighPrioConstraints();
}
public Collection<HardActivityConstraint> getLowPrioHardActivityConstraints() {
return actLevelConstraintManager.getLowPrioConstraints();
}
// public Collection<HardActivityConstraint> getHardActivityConstraints() {
// return actLevelConstraintManager.g;
// }
public DependencyType[] getDependencyTypes() {
return dependencyTypes;
}
@ -103,7 +123,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
constraintTypeKnown = true;
}
if (c instanceof HardRouteConstraint) {
routeLevelConstraintManager.addConstraint((HardRouteConstraint) c);
hardRouteConstraintManager.addConstraint((HardRouteConstraint) c);
constraintTypeKnown = true;
}
if (c instanceof SoftRouteConstraint) {
@ -152,7 +172,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
}
public void addConstraint(HardRouteConstraint routeLevelConstraint) {
routeLevelConstraintManager.addConstraint(routeLevelConstraint);
hardRouteConstraintManager.addConstraint(routeLevelConstraint);
}
public void addConstraint(SoftActivityConstraint softActivityConstraint) {
@ -165,7 +185,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
@Override
public boolean fulfilled(JobInsertionContext insertionContext) {
return routeLevelConstraintManager.fulfilled(insertionContext);
return hardRouteConstraintManager.fulfilled(insertionContext);
}
@Override
@ -176,7 +196,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
public Collection<Constraint> getConstraints() {
List<Constraint> constraints = new ArrayList<Constraint>();
constraints.addAll(actLevelConstraintManager.getAllConstraints());
constraints.addAll(routeLevelConstraintManager.getConstraints());
constraints.addAll(hardRouteConstraintManager.getConstraints());
constraints.addAll(softActivityConstraintManager.getConstraints());
constraints.addAll(softRouteConstraintManager.getConstraints());
return Collections.unmodifiableCollection(constraints);

View file

@ -0,0 +1,134 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.problem.constraint;
import com.graphhopper.jsprit.core.algorithm.state.StateId;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment;
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
import com.graphhopper.jsprit.core.problem.solution.route.activity.Start;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import java.util.Collection;
import java.util.Map;
/**
* Created by schroeder on 11/10/16.
*/
public class MaxDistanceConstraint implements HardActivityConstraint{
private StateManager stateManager;
private StateId distanceId;
private TransportDistance distanceCalculator;
private Double[] maxDistances;
public MaxDistanceConstraint(StateManager stateManager, StateId distanceId, TransportDistance distanceCalculator, Map<Vehicle,Double> maxDistancePerVehicleMap) {
this.stateManager = stateManager;
this.distanceId = distanceId;
this.distanceCalculator = distanceCalculator;
makeArray(maxDistancePerVehicleMap);
}
private void makeArray(Map<Vehicle, Double> maxDistances) {
int maxIndex = getMaxIndex(maxDistances.keySet());
this.maxDistances = new Double[maxIndex+1];
for(Vehicle v : maxDistances.keySet()){
this.maxDistances[v.getIndex()]=maxDistances.get(v);
}
}
private int getMaxIndex(Collection<Vehicle> vehicles) {
int index = 0;
for(Vehicle v : vehicles){
if(v.getIndex() > index) index = v.getIndex();
}
return index;
}
@Override
public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
if(!hasMaxDistance(iFacts.getNewVehicle())) return ConstraintsStatus.FULFILLED;
Double currentDistance = 0d;
boolean routeIsEmpty = iFacts.getRoute().isEmpty();
if(!routeIsEmpty){
currentDistance = stateManager.getRouteState(iFacts.getRoute(),iFacts.getNewVehicle(), distanceId,Double.class);
}
double maxDistance = getMaxDistance(iFacts.getNewVehicle());
if(currentDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED_BREAK;
double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle());
if(prevAct instanceof Start && nextAct instanceof End) distancePrevAct2NextAct = 0;
if(nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()){
distanceNewAct2nextAct = 0;
distancePrevAct2NextAct = 0;
}
double additionalDistance = distancePrevAct2NewAct + distanceNewAct2nextAct - distancePrevAct2NextAct;
if(currentDistance + additionalDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED;
double additionalDistanceOfPickup = 0;
if(newAct instanceof DeliverShipment){
int iIndexOfPickup = iFacts.getRelatedActivityContext().getInsertionIndex();
TourActivity pickup = iFacts.getAssociatedActivities().get(0);
TourActivity actBeforePickup;
if(iIndexOfPickup > 0) actBeforePickup = iFacts.getRoute().getActivities().get(iIndexOfPickup-1);
else actBeforePickup = new Start(iFacts.getNewVehicle().getStartLocation(),0,Double.MAX_VALUE);
TourActivity actAfterPickup;
if (iIndexOfPickup < iFacts.getRoute().getActivities().size())
actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup);
else
actAfterPickup = nextAct;
double distanceActBeforePickup2Pickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), pickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle());
double distancePickup2ActAfterPickup = distanceCalculator.getDistance(pickup.getLocation(), actAfterPickup.getLocation(), iFacts.getRelatedActivityContext().getEndTime(), iFacts.getNewVehicle());
double distanceBeforePickup2AfterPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle());
if (routeIsEmpty) distanceBeforePickup2AfterPickup = 0;
if (actAfterPickup instanceof End && !iFacts.getNewVehicle().isReturnToDepot()) {
distancePickup2ActAfterPickup = 0;
distanceBeforePickup2AfterPickup = 0;
}
additionalDistanceOfPickup = distanceActBeforePickup2Pickup + distancePickup2ActAfterPickup - distanceBeforePickup2AfterPickup;
}
if(currentDistance + additionalDistance + additionalDistanceOfPickup > maxDistance){
return ConstraintsStatus.NOT_FULFILLED;
}
return ConstraintsStatus.FULFILLED;
}
private boolean hasMaxDistance(Vehicle newVehicle){
if(newVehicle.getIndex() >= this.maxDistances.length) return false;
return this.maxDistances[newVehicle.getIndex()] != null;
}
private double getMaxDistance(Vehicle newVehicle) {
Double maxDistance = this.maxDistances[newVehicle.getIndex()];
if(maxDistance == null) return Double.MAX_VALUE;
return maxDistance;
}
}

View file

@ -20,21 +20,32 @@ package com.graphhopper.jsprit.core.problem.constraint;
import com.graphhopper.jsprit.core.algorithm.state.StateId;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.algorithm.state.UpdateMaxTimeInVehicle;
import com.graphhopper.jsprit.core.algorithm.state.UpdateVehicleDependentPracticalTimeWindows;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.cost.TransportTime;
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliveryActivity;
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
import com.graphhopper.jsprit.core.problem.solution.route.activity.PickupActivity;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import java.util.Map;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* Created by schroeder on 15/09/16.
*/
public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
private final VehicleRoutingProblem vrp;
private final TransportTime transportTime;
private final VehicleRoutingActivityCosts activityCosts;
@ -43,15 +54,19 @@ public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
private final StateManager stateManager;
public MaxTimeInVehicleConstraint(TransportTime transportTime, VehicleRoutingActivityCosts activityCosts, StateId latestStartId, StateManager stateManager) {
public MaxTimeInVehicleConstraint(TransportTime transportTime, VehicleRoutingActivityCosts activityCosts, StateId latestStartId, StateManager stateManager, VehicleRoutingProblem vrp) {
this.transportTime = transportTime;
this.latestStartId = latestStartId;
this.stateManager = stateManager;
this.activityCosts = activityCosts;
this.vrp = vrp;
}
@Override
public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
public ConstraintsStatus fulfilled(final JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
boolean newActIsPickup = newAct instanceof PickupActivity;
boolean newActIsDelivery = newAct instanceof DeliveryActivity;
boolean isShipment = iFacts.getJob() instanceof Shipment;
/*
1. check whether insertion of new shipment satisfies own max-in-vehicle-constraint
2. check whether insertion of new shipment satisfies all other max-in-vehicle-constraints
@ -75,7 +90,7 @@ public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
if(timeInVehicle > maxTimeInVehicle) return ConstraintsStatus.NOT_FULFILLED;
}
else if(newAct instanceof PickupActivity){
else if(newActIsPickup){
if(iFacts.getAssociatedActivities().size() == 1){
double maxTimeInVehicle = ((TourActivity.JobActivity)newAct).getJob().getMaxTimeInVehicle();
//ToDo - estimate in vehicle time of pickups here - This seems to trickier than I thought
@ -88,16 +103,47 @@ public class MaxTimeInVehicleConstraint implements HardActivityConstraint {
//************ 2. check whether insertion of new shipment satisfies all other max-in-vehicle-constraints
if(newActIsPickup || iFacts.getAssociatedActivities().size() == 1) {
double latest;
if(iFacts.getRoute().isEmpty()) latest = Double.MAX_VALUE;
else if(nextAct instanceof End){
latest = stateManager.getRouteState(iFacts.getRoute(),iFacts.getNewVehicle(), latestStartId,Double.class);
}
else latest = stateManager.getActivityState(nextAct, iFacts.getNewVehicle(), latestStartId, Double.class);
if (iFacts.getRoute().isEmpty()) latest = Double.MAX_VALUE;
else if (nextAct instanceof End) {
latest = stateManager.getRouteState(iFacts.getRoute(), iFacts.getNewVehicle(), latestStartId, Double.class);
} else latest = stateManager.getActivityState(nextAct, iFacts.getNewVehicle(), latestStartId, Double.class);
if(nextActStart > latest){
if (nextActStart > latest) {
return ConstraintsStatus.NOT_FULFILLED;
}
}
else if(newActIsDelivery && iFacts.getAssociatedActivities().size() == 2){
StateManager localStateManager = new StateManager(vrp);
StateId stateId = localStateManager.createStateId("local-slack");
UpdateMaxTimeInVehicle updateMaxTimeInVehicle = new UpdateMaxTimeInVehicle(localStateManager,stateId,transportTime,activityCosts);
updateMaxTimeInVehicle.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
@Override
public Collection<Vehicle> get(VehicleRoute route) {
return Arrays.asList(iFacts.getNewVehicle());
}
});
updateMaxTimeInVehicle.begin(iFacts.getRoute());
List<TourActivity> tourActivities = new ArrayList<>(iFacts.getRoute().getActivities());
tourActivities.add(iFacts.getRelatedActivityContext().getInsertionIndex(),iFacts.getAssociatedActivities().get(0));
for(TourActivity act : tourActivities){
updateMaxTimeInVehicle.visit(act);
}
updateMaxTimeInVehicle.finish(tourActivities,iFacts.getJob());
double latest;
if (iFacts.getRoute().isEmpty()) latest = Double.MAX_VALUE;
else if (nextAct instanceof End) {
latest = localStateManager.getRouteState(iFacts.getRoute(), iFacts.getNewVehicle(), stateId, Double.class);
} else latest = localStateManager.getActivityState(nextAct, iFacts.getNewVehicle(), stateId, Double.class);
if (nextActStart > latest) {
return ConstraintsStatus.NOT_FULFILLED;
}
}
return ConstraintsStatus.FULFILLED;
}

View file

@ -17,6 +17,8 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import java.util.Collection;
import com.graphhopper.jsprit.core.problem.AbstractJob;
import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.Location;
@ -26,8 +28,6 @@ import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindows;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsImpl;
import com.graphhopper.jsprit.core.util.Coordinate;
import java.util.Collection;
/**
* Service implementation of a job.
* <p>
@ -91,10 +91,9 @@ public class Service extends AbstractJob {
private boolean twAdded = false;
private int priority = 2;
protected Object userData;
protected double maxTimeInVehicle = Double.MAX_VALUE;
Builder(String id){
protected double maxTimeInVehicle = Double.MAX_VALUE;Builder(String id){
this.id = id;
timeWindows = new TimeWindowsImpl();
timeWindows.add(timeWindow);
@ -141,6 +140,24 @@ public class Service extends AbstractJob {
return this;
}
/**
* Sets user specific domain data associated with the object.
*
* <p>
* The user data is a black box for the framework, it only stores it,
* but never interacts with it in any way.
* </p>
*
* @param userData
* any object holding the domain specific user data
* associated with the object.
* @return builder
*/
public Builder<T> setUserData(Object userData) {
this.userData = userData;
return this;
}
/**
* Adds capacity dimension.
*
@ -216,15 +233,16 @@ public class Service extends AbstractJob {
}
/**
* Set priority to service. Only 1 = high priority, 2 = medium and 3 = low are allowed.
* Set priority to service. Only 1 (very high) to 10 (very low) are allowed.
* <p>
* Default is 2 = medium.
* Default is 2.
*
* @param priority
* @return builder
*/
public Builder<T> setPriority(int priority) {
if(priority < 1 || priority > 3) throw new IllegalArgumentException("incorrect priority. only 1 = high, 2 = medium and 3 = low is allowed");
if (priority < 1 || priority > 10)
throw new IllegalArgumentException("incorrect priority. only priority values from 1 to 10 are allowed where 1 = high and 10 is low");
this.priority = priority;
return this;
}
@ -259,7 +277,8 @@ public class Service extends AbstractJob {
private final double maxTimeInVehicle;
Service(Builder builder) {
Service(Builder<?> builder) {
setUserData(builder.userData);
id = builder.id;
serviceTime = builder.serviceTime;
timeWindow = builder.timeWindow;
@ -270,8 +289,7 @@ public class Service extends AbstractJob {
location = builder.location;
timeWindowManager = builder.timeWindows;
priority = builder.priority;
maxTimeInVehicle = builder.maxTimeInVehicle;
}
maxTimeInVehicle = builder.maxTimeInVehicle;}
public Collection<TimeWindow> getTimeWindows(){
return timeWindowManager.getTimeWindows();
@ -380,6 +398,7 @@ public class Service extends AbstractJob {
*
* @return priority
*/
@Override
public int getPriority() {
return priority;
}

View file

@ -17,6 +17,8 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import java.util.Collection;
import com.graphhopper.jsprit.core.problem.AbstractJob;
import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.Location;
@ -24,8 +26,6 @@ import com.graphhopper.jsprit.core.problem.Skills;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsImpl;
import java.util.Collection;
/**
* Shipment is an implementation of Job and consists of a pickup and a delivery of something.
@ -89,6 +89,8 @@ public class Shipment extends AbstractJob {
private int priority = 2;
public Object userData;
public double maxTimeInVehicle = Double.MAX_VALUE;
/**
@ -110,10 +112,29 @@ public class Shipment extends AbstractJob {
deliveryTimeWindows.add(deliveryTimeWindow);
}
/**
* Sets user specific domain data associated with the object.
*
* <p>
* The user data is a black box for the framework, it only stores it,
* but never interacts with it in any way.
* </p>
*
* @param userData
* any object holding the domain specific user data
* associated with the object.
* @return builder
*/
public Builder setUserData(Object userData) {
this.userData = userData;
return this;
}
/**
* Sets pickup location.
*
* @param pickupLocation pickup location
* @param pickupLocation
* pickup location
* @return builder
*/
public Builder setPickupLocation(Location pickupLocation) {
@ -271,7 +292,7 @@ public class Shipment extends AbstractJob {
}
/**
* Set priority to shipment. Only 1 = high priority, 2 = medium and 3 = low are allowed.
* Set priority to shipment. Only 1 (high) to 10 (low) are allowed.
* <p>
* Default is 2 = medium.
*
@ -279,7 +300,8 @@ public class Shipment extends AbstractJob {
* @return builder
*/
public Builder setPriority(int priority) {
if(priority < 1 || priority > 3) throw new IllegalArgumentException("incorrect priority. only 1 = high, 2 = medium and 3 = low is allowed");
if (priority < 1 || priority > 10)
throw new IllegalArgumentException("incorrect priority. only 1 (very high) to 10 (very low) are allowed");
this.priority = priority;
return this;
}
@ -326,6 +348,7 @@ public class Shipment extends AbstractJob {
private final double maxTimeInVehicle;
Shipment(Builder builder) {
setUserData(builder.userData);
this.id = builder.id;
this.pickupServiceTime = builder.pickupServiceTime;
this.pickupTimeWindow = builder.pickupTimeWindow;
@ -454,6 +477,7 @@ public class Shipment extends AbstractJob {
*
* @return priority
*/
@Override
public int getPriority() {
return priority;
}

View file

@ -19,6 +19,7 @@ package com.graphhopper.jsprit.core.problem.solution.route;
import com.graphhopper.jsprit.core.problem.AbstractActivity;
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.driver.Driver;
import com.graphhopper.jsprit.core.problem.driver.DriverImpl;
import com.graphhopper.jsprit.core.problem.job.*;
@ -196,16 +197,33 @@ public class VehicleRoute {
return this;
}
@Deprecated
public Builder addBreak(Break currentbreak) {
if (currentbreak == null) throw new IllegalArgumentException("break must not be null");
return addBreak(currentbreak, currentbreak.getTimeWindow());
}
@Deprecated
public Builder addBreak(Break currentbreak, TimeWindow timeWindow) {
if (currentbreak == null) throw new IllegalArgumentException("break must not be null");
return addService(currentbreak,timeWindow);
}
public Builder addBreak(Break currentbreak, TimeWindow timeWindow, Location location) {
if (currentbreak == null) throw new IllegalArgumentException("break must not be null");
return addBreakInternally(currentbreak, timeWindow, location);
}
private Builder addBreakInternally(Break currentBreak, TimeWindow timeWindow, Location breakLocation) {
List<AbstractActivity> acts = jobActivityFactory.createActivities(currentBreak);
BreakActivity act = (BreakActivity) acts.get(0);
act.setTheoreticalEarliestOperationStartTime(timeWindow.getStart());
act.setTheoreticalLatestOperationStartTime(timeWindow.getEnd());
act.setLocation(breakLocation);
tourActivities.addActivity(act);
return this;
}
/**
* Adds a pickup to this route.
*

View file

@ -72,6 +72,14 @@ public interface Vehicle extends HasId, HasIndex {
public abstract VehicleTypeKey getVehicleTypeIdentifier();
public abstract Skills getSkills();
/**
* @return User-specific domain data associated with the vehicle
*/
public Object getUserData();
public abstract Break getBreak();
// Switch to this as soon as we switct to Java 8:
// default Object getUserData() {
// return null;
// };
}

View file

@ -17,12 +17,13 @@
*/
package com.graphhopper.jsprit.core.problem.vehicle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.graphhopper.jsprit.core.problem.AbstractVehicle;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.Skills;
import com.graphhopper.jsprit.core.problem.job.Break;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
@ -130,6 +131,8 @@ public class VehicleImpl extends AbstractVehicle {
private Break aBreak;
private Object userData;
private Builder(String id) {
super();
this.id = id;
@ -148,16 +151,39 @@ public class VehicleImpl extends AbstractVehicle {
return this;
}
/**
* Sets user specific domain data associated with the object.
*
* <p>
* The user data is a black box for the framework, it only stores it,
* but never interacts with it in any way.
* </p>
*
* @param userData
* any object holding the domain specific user data
* associated with the object.
* @return builder
*/
public Builder setUserData(Object userData) {
this.userData = userData;
return this;
}
/**
* Sets the flag whether the vehicle must return to depot or not.
* <p>
* <p>If returnToDepot is true, the vehicle must return to specified end-location. If you
* omit specifying the end-location, vehicle returns to start-location (that must to be set). If
* you specify it, it returns to specified end-location.
* <p>
* <p>If returnToDepot is false, the end-location of the vehicle is endogenous.
* If returnToDepot is true, the vehicle must return to specified
* end-location. If you omit specifying the end-location, vehicle
* returns to start-location (that must to be set). If you specify it,
* it returns to specified end-location.
* <p>
* <p>
* If returnToDepot is false, the end-location of the vehicle is
* endogenous.
*
* @param returnToDepot true if vehicle need to return to depot, otherwise false
* @param returnToDepot
* true if vehicle need to return to depot, otherwise false
* @return this builder
*/
public Builder setReturnToDepot(boolean returnToDepot) {
@ -239,9 +265,8 @@ public class VehicleImpl extends AbstractVehicle {
if (startLocation != null && endLocation == null) {
endLocation = startLocation;
}
if (startLocation == null && endLocation == null) {
if (startLocation == null && endLocation == null)
throw new IllegalArgumentException("vehicle requires startLocation. but neither locationId nor locationCoord nor startLocationId nor startLocationCoord has been set");
}
skills = skillBuilder.build();
return new VehicleImpl(this);
}
@ -297,6 +322,7 @@ public class VehicleImpl extends AbstractVehicle {
private final Break aBreak;
private VehicleImpl(Builder builder) {
setUserData(builder.userData);
id = builder.id;
type = builder.type;
earliestDeparture = builder.earliestStart;
@ -306,7 +332,7 @@ public class VehicleImpl extends AbstractVehicle {
endLocation = builder.endLocation;
startLocation = builder.startLocation;
aBreak = builder.aBreak;
// setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(),startLocation.getId(),endLocation.getId(),earliestDeparture,latestArrival,skills));
// setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(),startLocation.getId(),endLocation.getId(),earliestDeparture,latestArrival,skills));
setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(), startLocation.getId(), endLocation.getId(), earliestDeparture, latestArrival, skills, returnToDepot));
}
@ -346,6 +372,7 @@ public class VehicleImpl extends AbstractVehicle {
return id;
}
@Override
public boolean isReturnToDepot() {
return returnToDepot;
}

View file

@ -56,4 +56,13 @@ public interface VehicleType {
public String getProfile();
/**
* @return User-specific domain data associated with the vehicle type
*/
public Object getUserData();
// Switch to this as soon as we switct to Java 8:
// default Object getUserData() {
// return null;
// };
}

View file

@ -116,16 +116,39 @@ public class VehicleTypeImpl implements VehicleType {
private boolean dimensionAdded = false;
private Object userData;
private Builder(String id) {
this.id = id;
}
/**
* Sets the maximum velocity this vehicle-type can go [in meter per seconds].
* Sets user specific domain data associated with the object.
*
* <p>
* The user data is a black box for the framework, it only stores it,
* but never interacts with it in any way.
* </p>
*
* @param userData
* any object holding the domain specific user data
* associated with the object.
* @return builder
*/
public Builder setUserData(Object userData) {
this.userData = userData;
return this;
}
/**
* Sets the maximum velocity this vehicle-type can go [in meter per
* seconds].
*
* @param inMeterPerSeconds
* @return this builder
* @throws IllegalArgumentException if velocity is smaller than zero
* @throws IllegalArgumentException
* if velocity is smaller than zero
*/
public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds) {
if (inMeterPerSeconds < 0.0) throw new IllegalArgumentException("velocity cannot be smaller than zero");
@ -314,12 +337,15 @@ public class VehicleTypeImpl implements VehicleType {
private final double maxVelocity;
private Object userData;
/**
* priv constructor constructing vehicle-type
*
* @param builder
*/
private VehicleTypeImpl(VehicleTypeImpl.Builder builder) {
this.userData = builder.userData;
typeId = builder.id;
capacity = builder.capacity;
maxVelocity = builder.maxVelo;
@ -328,6 +354,14 @@ public class VehicleTypeImpl implements VehicleType {
profile = builder.profile;
}
/**
* @return User-specific domain data associated with the vehicle
*/
@Override
public Object getUserData() {
return userData;
}
/* (non-Javadoc)
* @see basics.route.VehicleType#getTypeId()
*/

View file

@ -45,6 +45,8 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
private double[][][] matrix;
private final int noLocations;
/**
* Creates a new builder returning the matrix-builder.
* <p>If you want to consider symmetric matrices, set isSymmetric to true.
@ -59,6 +61,7 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
private Builder(int noLocations, boolean isSymmetric) {
this.isSymmetric = isSymmetric;
matrix = new double[noLocations][noLocations][2];
this.noLocations = noLocations;
}
/**
@ -74,11 +77,11 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
return this;
}
private void add(int fromIndex, int toIndex, int indicatorIndex, double distance) {
private void add(int fromIndex, int toIndex, int indicatorIndex, double value) {
if (isSymmetric) {
if (fromIndex < toIndex) matrix[fromIndex][toIndex][indicatorIndex] = distance;
else matrix[toIndex][fromIndex][indicatorIndex] = distance;
} else matrix[fromIndex][toIndex][indicatorIndex] = distance;
if (fromIndex < toIndex) matrix[fromIndex][toIndex][indicatorIndex] = value;
else matrix[toIndex][fromIndex][indicatorIndex] = value;
} else matrix[fromIndex][toIndex][indicatorIndex] = value;
}
/**
@ -94,6 +97,11 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
return this;
}
public Builder addTransportTimeAndDistance(int fromIndex, int toIndex, double time, double distance){
addTransportTime(fromIndex, toIndex, time);
addTransportDistance(fromIndex,toIndex,distance);
return this;
}
/**
* Builds the matrix.
*
@ -110,9 +118,12 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
private final double[][][] matrix;
private int noLocations;
private FastVehicleRoutingTransportCostsMatrix(Builder builder) {
this.isSymmetric = builder.isSymmetric;
matrix = builder.matrix;
noLocations = builder.noLocations;
}
/**
@ -169,4 +180,9 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
return costParams.perDistanceUnit * getDistance(from.getIndex(), to.getIndex()) + costParams.perTransportTimeUnit * getTransportTime(from, to, departureTime, driver, vehicle);
}
public int getNoLocations() {
return noLocations;
}
}

View file

@ -0,0 +1,181 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.util;
import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobUnassignedListener;
import com.graphhopper.jsprit.core.problem.job.Job;
import org.apache.commons.math3.stat.Frequency;
import java.util.*;
/**
* Created by schroeder on 06/02/17.
*/
public class UnassignedJobReasonTracker implements JobUnassignedListener {
public static String getMostLikelyFailedConstraintName(Frequency failedConstraintNamesFrequency) {
if (failedConstraintNamesFrequency == null) return "no reason found";
Iterator<Map.Entry<Comparable<?>, Long>> entryIterator = failedConstraintNamesFrequency.entrySetIterator();
int maxCount = 0;
String mostLikely = null;
while (entryIterator.hasNext()) {
Map.Entry<Comparable<?>, Long> entry = entryIterator.next();
if (entry.getValue() > maxCount) {
Comparable<?> key = entry.getKey();
mostLikely = key.toString();
}
}
return mostLikely;
}
Map<String, Frequency> failedConstraintNamesFrequencyMapping = new HashMap<>();
Map<Integer, String> codesToHumanReadableReason = new HashMap<>();
Map<String, Integer> failedConstraintNamesToCode = new HashMap<>();
Set<String> failedConstraintNamesToBeIgnored = new HashSet<>();
public UnassignedJobReasonTracker() {
codesToHumanReadableReason.put(1, "cannot serve required skill");
codesToHumanReadableReason.put(2, "cannot be visited within time window");
codesToHumanReadableReason.put(3, "does not fit into any vehicle due to capacity");
codesToHumanReadableReason.put(4, "cannot be assigned due to max distance constraint of vehicle");
failedConstraintNamesToCode.put("HardSkillConstraint", 1);
failedConstraintNamesToCode.put("VehicleDependentTimeWindowConstraints", 2);
failedConstraintNamesToCode.put("ServiceLoadRouteLevelConstraint", 3);
failedConstraintNamesToCode.put("PickupAndDeliverShipmentLoadActivityLevelConstraint", 3);
failedConstraintNamesToCode.put("ServiceLoadActivityLevelConstraint", 3);
failedConstraintNamesToCode.put("MaxDistanceConstraint", 4);
}
public void ignore(String simpleNameOfConstraint) {
failedConstraintNamesToBeIgnored.add(simpleNameOfConstraint);
}
@Override
public void informJobUnassigned(Job unassigned, Collection<String> failedConstraintNames) {
if (!this.failedConstraintNamesFrequencyMapping.containsKey(unassigned.getId())) {
this.failedConstraintNamesFrequencyMapping.put(unassigned.getId(), new Frequency());
}
for (String r : failedConstraintNames) {
if (failedConstraintNamesToBeIgnored.contains(r)) continue;
this.failedConstraintNamesFrequencyMapping.get(unassigned.getId()).addValue(r);
}
}
public void put(String simpleNameOfFailedConstraint, int code, String reason) {
if (code <= 20)
throw new IllegalArgumentException("first 20 codes are reserved internally. choose a code > 20");
codesToHumanReadableReason.put(code, reason);
if (failedConstraintNamesToCode.containsKey(simpleNameOfFailedConstraint)) {
throw new IllegalArgumentException(simpleNameOfFailedConstraint + " already assigned to code and reason");
} else failedConstraintNamesToCode.put(simpleNameOfFailedConstraint, code);
}
/**
* For each job id, it returns frequency distribution of failed constraints (simple name of constraint) in an unmodifiable map.
*
* @return
*/
@Deprecated
public Map<String, Frequency> getReasons() {
return Collections.unmodifiableMap(failedConstraintNamesFrequencyMapping);
}
/**
* For each job id, it returns frequency distribution of failed constraints (simple name of constraint) in an unmodifiable map.
*
* @return
*/
public Map<String, Frequency> getFailedConstraintNamesFrequencyMapping() {
return Collections.unmodifiableMap(failedConstraintNamesFrequencyMapping);
}
/**
* Returns an unmodifiable map of codes and reason pairs.
*
* @return
*/
public Map<Integer, String> getCodesToReason() {
return Collections.unmodifiableMap(codesToHumanReadableReason);
}
/**
* Returns an unmodifiable map of constraint names (simple name of constraint) and reason code pairs.
*
* @return
*/
public Map<String, Integer> getFailedConstraintNamesToCode() {
return Collections.unmodifiableMap(failedConstraintNamesToCode);
}
public int getCode(String failedConstraintName) {
return toCode(failedConstraintName);
}
public String getHumanReadableReason(int code) {
return getCodesToReason().get(code);
}
public String getHumanReadableReason(String failedConstraintName) {
return getCodesToReason().get(getCode(failedConstraintName));
}
/**
* Returns the most likely reason code i.e. the reason (failed constraint) being observed most often.
*
* 1 --> "cannot serve required skill
* 2 --> "cannot be visited within time window"
* 3 --> "does not fit into any vehicle due to capacity"
* 4 --> "cannot be assigned due to max distance constraint of vehicle"
*
* @param jobId
* @return
*/
public int getMostLikelyReasonCode(String jobId) {
if (!this.failedConstraintNamesFrequencyMapping.containsKey(jobId)) return -1;
Frequency reasons = this.failedConstraintNamesFrequencyMapping.get(jobId);
String mostLikelyReason = getMostLikelyFailedConstraintName(reasons);
return toCode(mostLikelyReason);
}
/**
* Returns the most likely reason i.e. the reason (failed constraint) being observed most often.
*
* @param jobId
* @return
*/
public String getMostLikelyReason(String jobId) {
if (!this.failedConstraintNamesFrequencyMapping.containsKey(jobId)) return "no reason found";
Frequency reasons = this.failedConstraintNamesFrequencyMapping.get(jobId);
String mostLikelyReason = getMostLikelyFailedConstraintName(reasons);
int code = toCode(mostLikelyReason);
if (code == -1) return mostLikelyReason;
else return codesToHumanReadableReason.get(code);
}
private int toCode(String mostLikelyReason) {
if (failedConstraintNamesToCode.containsKey(mostLikelyReason))
return failedConstraintNamesToCode.get(mostLikelyReason);
else return -1;
}
}

View file

@ -31,7 +31,6 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.reporting.SolutionPrinter;
import com.graphhopper.jsprit.core.util.Solutions;
import org.junit.Assert;
import org.junit.Test;
/**
@ -43,10 +42,10 @@ public class MaxTimeInVehicle_IT {
public void test(){
Shipment s1 = Shipment.Builder.newInstance("s1").setPickupLocation(Location.newInstance(0,0)).setDeliveryLocation(Location.newInstance(100,0)).setDeliveryServiceTime(10)
.setMaxTimeInVehicle(90d)
.setMaxTimeInVehicle(100d)
.build();
Shipment s2 = Shipment.Builder.newInstance("s2").setPickupLocation(Location.newInstance(0,0)).setDeliveryLocation(Location.newInstance(100,0)).setDeliveryServiceTime(10)
.setMaxTimeInVehicle(90d)
.setMaxTimeInVehicle(100d)
.build();
VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
@ -58,12 +57,12 @@ public class MaxTimeInVehicle_IT {
stateManager.addStateUpdater(new UpdateMaxTimeInVehicle(stateManager,id,vrp.getTransportCosts(),vrp.getActivityCosts()));
ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager);
constraintManager.addConstraint(new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts(),id,stateManager), ConstraintManager.Priority.CRITICAL);
constraintManager.addConstraint(new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts(),id,stateManager, vrp), ConstraintManager.Priority.CRITICAL);
VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setStateAndConstraintManager(stateManager,constraintManager).buildAlgorithm();
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
Assert.assertEquals(400, solution.getCost(), 0.001);
// SolutionPrinter.print(vrp,solution, SolutionPrinter.Print.VERBOSE);
// Assert.assertEquals(400, solution.getCost(), 0.001);
SolutionPrinter.print(vrp,solution, SolutionPrinter.Print.VERBOSE);
}
}

View file

@ -26,14 +26,17 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.util.Solutions;
import com.graphhopper.jsprit.core.util.UnassignedJobReasonTracker;
import org.junit.Test;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class UnassignedJobListTest {
@Test
public void job2ShouldBeInBadJobList_dueToTimeWindow() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
@ -46,11 +49,17 @@ public class UnassignedJobListTest {
VehicleRoutingProblem vrp = builder.build();
VehicleRoutingAlgorithm algorithm = new GreedySchrimpfFactory().createAlgorithm(vrp);
algorithm.setMaxIterations(10);
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
algorithm.addListener(reasonTracker);
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions);
assertTrue(!solution.getUnassignedJobs().contains(job1));
assertTrue(solution.getUnassignedJobs().contains(job2));
assertEquals(2, reasonTracker.getMostLikelyReasonCode("job2"));
}
@Test
@ -63,13 +72,19 @@ public class UnassignedJobListTest {
builder.addJob(job2);
VehicleRoutingProblem vrp = builder.build();
VehicleRoutingAlgorithm algorithm = new GreedySchrimpfFactory().createAlgorithm(vrp);
algorithm.setMaxIterations(10);
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
algorithm.addListener(reasonTracker);
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions);
assertTrue(!solution.getUnassignedJobs().contains(job1));
assertTrue(solution.getUnassignedJobs().contains(job2));
assertEquals(3, reasonTracker.getMostLikelyReasonCode("job2"));
}
}

View file

@ -1,95 +0,0 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.AbstractJob;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.mock;
/**
* Created by schroeder on 15/08/16.
*/
public class ConfigureFixCostCalculatorTest {
VehicleRoutingProblem vrp;
@Before
public void before(){
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
for(int i=0;i<100;i++){
Service service = Service.Builder.newInstance("" + i).setLocation(Location.newInstance(0)).build();
vrpBuilder.addJob(service);
}
vrp = vrpBuilder.build();
}
@Test
public void shouldCalculateCorrectly(){
List<Job> unassigned = new ArrayList<>();
int count = 1;
for(String key : vrp.getJobs().keySet()) {
if(count <= 25) {
unassigned.add(vrp.getJobs().get(key));
}
count++;
}
JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class),mock(StateManager.class));
ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp,jicc);
c.informInsertionStarts(new ArrayList<VehicleRoute>(), unassigned);
Assert.assertEquals(0.75, jicc.getSolutionCompletenessRatio(), 0.001);
}
@Test
public void shouldBeMinRatio(){
List<Job> unassigned = new ArrayList<>();
int count = 1;
for(String key : vrp.getJobs().keySet()) {
if(count <= 75) {
unassigned.add(vrp.getJobs().get(key));
}
count++;
}
JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class),mock(StateManager.class));
ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp,jicc);
c.informInsertionStarts(new ArrayList<VehicleRoute>(), unassigned);
Assert.assertEquals(0.5, jicc.getSolutionCompletenessRatio(), 0.001);
}
@Test
public void shouldBeOne(){
List<Job> unassigned = new ArrayList<>();
JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class),mock(StateManager.class));
ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp,jicc);
c.informInsertionStarts(new ArrayList<VehicleRoute>(), unassigned);
Assert.assertEquals(1.0, jicc.getSolutionCompletenessRatio(), 0.001);
}
}

View file

@ -20,6 +20,7 @@ package com.graphhopper.jsprit.core.algorithm.recreate;
import com.graphhopper.jsprit.core.algorithm.state.InternalStates;
import com.graphhopper.jsprit.core.problem.Capacity;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
@ -34,11 +35,15 @@ import static org.mockito.Mockito.when;
public class JobInsertionConsideringFixCostsCalculatorTest {
private JobInsertionConsideringFixCostsCalculator calc;
private IncreasingAbsoluteFixedCosts absFixedCosts;
private Vehicle oVehicle;
private DecreasingRelativeFixedCosts relFixedCosts;
private Vehicle nVehicle;
private Vehicle small;
private Vehicle medium;
private Vehicle large;
private Job job;
@ -52,194 +57,333 @@ public class JobInsertionConsideringFixCostsCalculatorTest {
job = mock(Job.class);
when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).build());
oVehicle = mock(Vehicle.class);
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).setFixedCost(50.0).build();
when(oVehicle.getType()).thenReturn(oType);
small = mock(Vehicle.class);
VehicleType smallType = VehicleTypeImpl.Builder.newInstance("smallType").addCapacityDimension(0, 50).setFixedCost(50.0).build();
when(small.getType()).thenReturn(smallType);
nVehicle = mock(Vehicle.class);
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).setFixedCost(100.0).build();
when(nVehicle.getType()).thenReturn(type);
medium = mock(Vehicle.class);
VehicleType mediumType = VehicleTypeImpl.Builder.newInstance("mediumType").addCapacityDimension(0, 100).setFixedCost(100.0).build();
when(medium.getType()).thenReturn(mediumType);
InsertionData iData = new InsertionData(0.0, 1, 1, nVehicle, null);
large = mock(Vehicle.class);
VehicleType largeType = VehicleTypeImpl.Builder.newInstance("largeType").addCapacityDimension(0, 400).setFixedCost(200.0).build();
when(large.getType()).thenReturn(largeType);
InsertionData iData = new InsertionData(0.0, 1, 1, medium, null);
route = mock(VehicleRoute.class);
when(jobInsertionCosts.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE)).thenReturn(iData);
when(jobInsertionCosts.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE)).thenReturn(iData);
when(jobInsertionCosts.getInsertionData(route, job, large, 0.0, null, Double.MAX_VALUE)).thenReturn(new InsertionData(0.0, 1, 1, large, null));
stateGetter = mock(RouteAndActivityStateGetter.class);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().build());
calc = new JobInsertionConsideringFixCostsCalculator(jobInsertionCosts, stateGetter);
absFixedCosts = new IncreasingAbsoluteFixedCosts(10);
relFixedCosts = new DecreasingRelativeFixedCosts(stateGetter, 10);
}
@Test
public void whenOldVehicleIsNullAndSolutionComplete_itShouldReturnFixedCostsOfNewVehicle() {
calc.setSolutionCompletenessRatio(1.0);
calc.setWeightOfFixCost(1.0);
absFixedCosts.setSolutionCompletenessRatio(1.0);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(1.0);
relFixedCosts.setWeightOfFixCost(1.0);
//(1.*absFix + 0.*relFix) * completeness * weight = (1.*100. + 0.*50.) * 1. * 1. = 100.
assertEquals(100., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
assertEquals(100., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs0PercentComplete_itShouldReturnNoFixedCosts() {
calc.setSolutionCompletenessRatio(0.0);
calc.setWeightOfFixCost(1.0);
absFixedCosts.setSolutionCompletenessRatio(0.0);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.0);
relFixedCosts.setWeightOfFixCost(1.0);
//(0.*absFix + 1.*relFix) * completeness * weight = 0.
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.1);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs50PercentComplete_itShouldReturnAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
calc.setSolutionCompletenessRatio(0.5);
calc.setWeightOfFixCost(1.0);
absFixedCosts.setSolutionCompletenessRatio(0.5);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.5);
relFixedCosts.setWeightOfFixCost(1.0);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 1. = (0.5*100+0.5*50)*0.5*1. = 37.5
assertEquals(37.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(37.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs75PercentComplete_itShouldReturnAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(1.0);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(1.0);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 1.= (0.75*100.+0.25*50.)*0.75*1. = 65.625
assertEquals(65.625, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(65.625, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionCompleteAndWeightIs05_itShouldReturnHalfOfFixedCostsOfNewVehicle() {
calc.setSolutionCompletenessRatio(1.0);
calc.setWeightOfFixCost(.5);
absFixedCosts.setSolutionCompletenessRatio(1.0);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(1.0);
relFixedCosts.setWeightOfFixCost(.5);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(1.*absFix + 0.*relFix) * 1. * 0.5 = (1.*100. + 0.*50.) * 1. * 0.5 = 5.
assertEquals(50., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(50., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs0PercentCompleteAndWeightIs05_itShouldReturnHalfOfNoFixedCosts() {
calc.setSolutionCompletenessRatio(0.0);
calc.setWeightOfFixCost(.5);
absFixedCosts.setSolutionCompletenessRatio(0.0);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(0.0);
relFixedCosts.setWeightOfFixCost(.5);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.*absFix + 1.*relFix) * 0. * .5 = 0.
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnHalfOfAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
calc.setSolutionCompletenessRatio(0.5);
calc.setWeightOfFixCost(.5);
absFixedCosts.setSolutionCompletenessRatio(0.5);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(0.5);
relFixedCosts.setWeightOfFixCost(.5);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*100+0.5*50)*0.5*0.5 = 18.75
assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNullAndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnHalfOfAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(0.5);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(0.5);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(0.5);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*100.+0.25*50.)*0.75*0.5 = 32.8125
assertEquals(32.8125, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(32.8125, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionComplete_itShouldReturnHalfOfFixedCostsOfNewVehicle() {
calc.setSolutionCompletenessRatio(1.0);
calc.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(1.0);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(1.0);
relFixedCosts.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(1.*absFix + 0.*relFix) * completeness * weight = (1.*(100.-50.) + 0.*(50.-0.)) * 1. * 1. = 50.
assertEquals(50., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(50., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs0PercentComplete_itShouldReturnNoFixedCosts() {
calc.setSolutionCompletenessRatio(0.0);
calc.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.0);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.0);
relFixedCosts.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.*absFix + 1.*relFix) * completeness * weight = 0.
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs50PercentComplete_itShouldCorrectVal() {
calc.setSolutionCompletenessRatio(0.5);
calc.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.5);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.5);
relFixedCosts.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 1. = (0.5*(100-50)+0.5*(50-0))*0.5*1. = 25.
assertEquals(25., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(25., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs75PercentComplete_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(1.0);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(1.0);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 1.= (0.75*(100.-50.)+0.25*(50.-0.))*0.75*1. = 37.5
assertEquals(37.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(37.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(1.0);
calc.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(1.0);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(1.0);
relFixedCosts.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(1.*absFix + 0.*relFix) * 1. * 0.5 = (1.*(100.-50.) + 0.*(50.-0.)) * 1. * 0.5 = 25.
assertEquals(25., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(25., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs0PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.0);
calc.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.0);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(0.0);
relFixedCosts.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.*absFix + 1.*relFix) * 0. * .5 = 0.
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.5);
calc.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.5);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(0.5);
relFixedCosts.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(50-0))*0.5*0.5 = 12.5
assertEquals(12.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(12.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(0.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(0.5);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(0.5);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*(50.-0.))*0.75*0.5 = 18.75
assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.5);
calc.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.5);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(0.5);
relFixedCosts.setWeightOfFixCost(.5);
when(route.getVehicle()).thenReturn(small);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).build());
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5
assertEquals(12.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(12.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(0.5);
when(route.getVehicle()).thenReturn(oVehicle);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(0.5);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(0.5);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*(75.-25.))*0.75*0.5 = 18.75
assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs50PercentCompleteAndWeightIs05WithMultipleCapDims_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(.5);
calc.setWeightOfFixCost(.5);
absFixedCosts.setSolutionCompletenessRatio(.5);
absFixedCosts.setWeightOfFixCost(.5);
relFixedCosts.setSolutionCompletenessRatio(.5);
relFixedCosts.setWeightOfFixCost(.5);
when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
when(oVehicle.getType()).thenReturn(oType);
when(small.getType()).thenReturn(oType);
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
when(nVehicle.getType()).thenReturn(type);
when(medium.getType()).thenReturn(type);
when(route.getVehicle()).thenReturn(oVehicle);
when(route.getVehicle()).thenReturn(small);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5
/*
* (0.5*(100-50)+0.5*(
* relFixNew - relFixOld = (75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.) =
* )*0.5*0.5
* = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5
* = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125
*/
assertEquals(7.8125, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}
@Test
public void whenOldVehicleIsMoreExpensive() {
absFixedCosts.setSolutionCompletenessRatio(1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(1);
relFixedCosts.setWeightOfFixCost(1);
when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
when(medium.getType()).thenReturn(oType);
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
when(small.getType()).thenReturn(type);
when(route.getVehicle()).thenReturn(small);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5
/*
@ -249,26 +393,125 @@ public class JobInsertionConsideringFixCostsCalculatorTest {
* = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5
* = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125
*/
assertEquals(7.8125, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(-50d, insertionCost, 0.01);
}
@Test
public void smallVSMediumAbsCosts() {
absFixedCosts.setSolutionCompletenessRatio(1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(1);
relFixedCosts.setWeightOfFixCost(1);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(50d, insertionCost, 0.01);
}
@Test
public void smallVSLargeAbsCosts() {
absFixedCosts.setSolutionCompletenessRatio(1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(1);
relFixedCosts.setWeightOfFixCost(1);
when(route.getVehicle()).thenReturn(small);
JobInsertionContext context = new JobInsertionContext(route, job, large, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(150d, insertionCost, 0.01);
}
@Test
public void largeVSMediumAbsCosts() {
absFixedCosts.setSolutionCompletenessRatio(1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(1);
relFixedCosts.setWeightOfFixCost(1);
when(route.getVehicle()).thenReturn(large);
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(-100d, insertionCost, 0.01);
}
@Test
public void mediumVSLargeAbsCosts() {
absFixedCosts.setSolutionCompletenessRatio(1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(1);
relFixedCosts.setWeightOfFixCost(1);
when(route.getVehicle()).thenReturn(medium);
JobInsertionContext context = new JobInsertionContext(route, job, large, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(100d, insertionCost, 0.01);
}
@Test
public void whenOldVehicleIsMoreExpensive2() {
absFixedCosts.setSolutionCompletenessRatio(0.1);
absFixedCosts.setWeightOfFixCost(1);
relFixedCosts.setSolutionCompletenessRatio(0.1);
relFixedCosts.setWeightOfFixCost(1);
when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
when(medium.getType()).thenReturn(oType);
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
when(small.getType()).thenReturn(type);
when(route.getVehicle()).thenReturn(small);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
/*
job = 50
abs = (50 - 100) * 0.1 * 0.1 * 1.0 = -0.5
rel = ( (75/50+100/100)/2 * 50 - (25/100 + 100/400)/2 * 100) * 0.9 * 0.1 = 3.375
c = -0.5 + 3.375 = 2.875
*/
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
assertEquals(2.875, insertionCost, 0.01);
}
@Test
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs75PercentCompleteAndWeightIs05WithMultipleCapDims_itShouldReturnCorrectVal() {
calc.setSolutionCompletenessRatio(0.75);
calc.setWeightOfFixCost(0.5);
absFixedCosts.setSolutionCompletenessRatio(0.75);
absFixedCosts.setWeightOfFixCost(0.5);
relFixedCosts.setSolutionCompletenessRatio(0.75);
relFixedCosts.setWeightOfFixCost(0.5);
when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
when(oVehicle.getType()).thenReturn(oType);
when(small.getType()).thenReturn(oType);
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
when(nVehicle.getType()).thenReturn(type);
when(medium.getType()).thenReturn(type);
when(route.getVehicle()).thenReturn(oVehicle);
when(route.getVehicle()).thenReturn(small);
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*12.5)*0.75*0.5 = 15.234375
assertEquals(15.234375, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
assertEquals(15.234375, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
}

View file

@ -178,7 +178,7 @@ public class ShipmentInsertionCalculatorTest {
insertionCalculator.setJobActivityFactory(activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(InsertionData.createEmptyInsertionData(), iData);
assertTrue(iData instanceof InsertionData.NoInsertionFound);
}

View file

@ -28,6 +28,7 @@ import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import com.graphhopper.jsprit.core.problem.cost.WaitingTimeCosts;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
@ -91,6 +92,74 @@ public class TestLocalActivityInsertionCostsCalculator {
return Location.Builder.newInstance().setId(i).build();
}
@Test
public void whenAddingServiceBetweenDiffStartAndEnd_costMustBeCorrect() {
VehicleImpl v = VehicleImpl.Builder.newInstance("v")
.setStartLocation(Location.newInstance(0, 0))
.setEndLocation(Location.newInstance(20, 0))
.build();
Service s = Service.Builder.newInstance("s")
.setLocation(Location.newInstance(10, 0))
.build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
.addVehicle(v)
.addJob(s)
.build();
VehicleRoute route = VehicleRoute.emptyRoute();
JobInsertionContext jobInsertionContext =
new JobInsertionContext(route, s, v, null, 0);
LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator =
new LocalActivityInsertionCostsCalculator(
vrp.getTransportCosts(),
vrp.getActivityCosts(),
new StateManager(vrp));
double cost = localActivityInsertionCostsCalculator.getCosts(
jobInsertionContext,
new Start(v.getStartLocation(),0,Double.MAX_VALUE),
new End(v.getEndLocation(),0,Double.MAX_VALUE),
vrp.getActivities(s).get(0),
0);
assertEquals(20., cost, Math.ulp(20.));
}
@Test
public void whenAddingShipmentBetweenDiffStartAndEnd_costMustBeCorrect() {
VehicleImpl v = VehicleImpl.Builder.newInstance("v")
.setStartLocation(Location.newInstance(0, 0))
.setEndLocation(Location.newInstance(20, 0))
.build();
Shipment s = Shipment.Builder.newInstance("p")
.setPickupLocation(Location.newInstance(10, 0))
.setDeliveryLocation(Location.newInstance(10, 7.5))
.build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
.addVehicle(v)
.addJob(s)
.build();
VehicleRoute route = VehicleRoute.emptyRoute();
JobInsertionContext jobInsertionContext =
new JobInsertionContext(route, s, v, null, 0);
LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator =
new LocalActivityInsertionCostsCalculator(
vrp.getTransportCosts(),
vrp.getActivityCosts(),
new StateManager(vrp));
double cost = localActivityInsertionCostsCalculator.getCosts(
jobInsertionContext,
new Start(v.getStartLocation(),0,Double.MAX_VALUE),
new End(v.getEndLocation(),0,Double.MAX_VALUE),
vrp.getActivities(s).get(0),
0);
assertEquals(20., cost, Math.ulp(20.));
cost = localActivityInsertionCostsCalculator.getCosts(
jobInsertionContext,
vrp.getActivities(s).get(0),
new End(v.getEndLocation(),0,Double.MAX_VALUE),
vrp.getActivities(s).get(1),
0);
assertEquals(10, cost, Math.ulp(10.));
}
@Test
public void whenInsertingActBetweenTwoRouteActs_itCalcsMarginalTpCosts() {
TourActivity prevAct = mock(TourActivity.class);

View file

@ -0,0 +1,87 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.ruin;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
/**
* Created by schroeder on 13/01/17.
*/
public class StringUtilTest {
@Test
public void test() {
int stringLength = 4;
int seedIndex = 4;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(4, bounds.size());
Assert.assertEquals(1, (int) bounds.get(0));
Assert.assertEquals(2, (int) bounds.get(1));
Assert.assertEquals(3, (int) bounds.get(2));
Assert.assertEquals(4, (int) bounds.get(3));
}
@Test
public void test2() {
int stringLength = 4;
int seedIndex = 2;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(3, bounds.size());
Assert.assertEquals(0, (int) bounds.get(0));
Assert.assertEquals(1, (int) bounds.get(1));
Assert.assertEquals(2, (int) bounds.get(2));
}
@Test
public void test3() {
int stringLength = 4;
int seedIndex = 0;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(1, bounds.size());
Assert.assertEquals(0, (int) bounds.get(0));
}
@Test
public void test4() {
int stringLength = 4;
int seedIndex = 9;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(1, bounds.size());
Assert.assertEquals(6, (int) bounds.get(0));
}
@Test
public void test5() {
int stringLength = 4;
int seedIndex = 8;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(2, bounds.size());
Assert.assertEquals(5, (int) bounds.get(0));
Assert.assertEquals(6, (int) bounds.get(1));
}
}

View file

@ -18,10 +18,18 @@
package com.graphhopper.jsprit.core.problem;
import com.graphhopper.jsprit.core.util.Coordinate;
import junit.framework.Assert;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import com.graphhopper.jsprit.core.util.Coordinate;
/**
* Created by schroeder on 16.12.14.
*/
@ -34,6 +42,12 @@ public class LocationTest {
Assert.assertTrue(true);
}
@Test
public void whenNameSet_buildLocation() {
Location l = Location.Builder.newInstance().setName("mystreet 6a").setIndex(1).build();
Assert.assertEquals("mystreet 6a",l.getName());
}
@Test
public void whenIndexSetWitFactory_returnCorrectLocation() {
Location l = Location.newInstance(1);
@ -68,19 +82,31 @@ public class LocationTest {
@Test
public void whenCoordinateSet_build() {
Location l = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 20)).build();
Assert.assertEquals(10., l.getCoordinate().getX());
Assert.assertEquals(20., l.getCoordinate().getY());
Assert.assertEquals(10., l.getCoordinate().getX(),0.001);
Assert.assertEquals(20., l.getCoordinate().getY(),0.001);
Assert.assertTrue(true);
}
@Test
public void whenCoordinateSetWithFactory_returnCorrectLocation() {
// Location l = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10,20)).build();
// Location l = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10,20)).build();
Location l = Location.newInstance(10, 20);
Assert.assertEquals(10., l.getCoordinate().getX());
Assert.assertEquals(20., l.getCoordinate().getY());
Assert.assertEquals(10., l.getCoordinate().getX(),0.001);
Assert.assertEquals(20., l.getCoordinate().getY(),0.001);
Assert.assertTrue(true);
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheLocation() {
Location one = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 20))
.setUserData(new HashMap<String, Object>()).build();
Location two = Location.Builder.newInstance().setIndex(1).setUserData(42).build();
Location three = Location.Builder.newInstance().setIndex(2).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
}

View file

@ -31,6 +31,7 @@ import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.misc.ActivityContext;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
@ -47,7 +48,9 @@ public class MaxTimeInVehicleConstraintTest {
Delivery d1;
Shipment shipment;
Shipment s1;
Shipment s2;
Delivery d2;
@ -68,8 +71,13 @@ public class MaxTimeInVehicleConstraintTest {
private void ini(double maxTime){
d1 = Delivery.Builder.newInstance("d1").setLocation(Location.newInstance(10,0)).build();
shipment = Shipment.Builder.newInstance("shipment").setPickupLocation(Location.newInstance(20,0))
s1 = Shipment.Builder.newInstance("s1").setPickupLocation(Location.newInstance(20,0))
.setDeliveryLocation(Location.newInstance(40,0)).setMaxTimeInVehicle(maxTime).build();
s2 = Shipment.Builder.newInstance("s2").setPickupLocation(Location.newInstance(20,0))
.setDeliveryLocation(Location.newInstance(40,0)).setMaxTimeInVehicle(maxTime).build();
d2 = Delivery.Builder.newInstance("d2").setLocation(Location.newInstance(30,0)).setServiceTime(10).build();
p1 = Pickup.Builder.newInstance("p1").setLocation(Location.newInstance(10, 0)).build();
@ -77,11 +85,59 @@ public class MaxTimeInVehicleConstraintTest {
v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
vrp = VehicleRoutingProblem.Builder.newInstance().addJob(d1).addJob(shipment).addJob(d2).addJob(p1).addJob(p2)
vrp = VehicleRoutingProblem.Builder.newInstance().addJob(d1).addJob(s1).addJob(d2).addJob(p1).addJob(p2)
.addVehicle(v).build();
route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory())
.addDelivery(d1).addPickup(shipment).addDelivery(shipment).build();
.addDelivery(d1).addPickup(s1).addDelivery(s1).build();
}
@Test
public void shiftOfExistingShipmentsShouldWork(){
Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
Shipment s1 = Shipment.Builder.newInstance("s1").setPickupLocation(Location.newInstance(20,0))
.setDeliveryLocation(Location.newInstance(40,0)).setMaxTimeInVehicle(20).build();
Shipment s2 = Shipment.Builder.newInstance("s2").setPickupLocation(Location.newInstance(20,0))
.setPickupServiceTime(10)
.setDeliveryLocation(Location.newInstance(40,0)).setMaxTimeInVehicle(20).build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addVehicle(v).build();
VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory())
.addPickup(s1).addDelivery(s1).build();
StateManager stateManager = new StateManager(vrp);
StateId latestStartId = stateManager.createStateId("latest-start-id");
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(route,s2,v,route.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s2);
c.getAssociatedActivities().add(acts.get(0));
c.getAssociatedActivities().add(acts.get(1));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, route.getStart(), acts.get(0), route.getActivities().get(0), 0));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED, constraint.fulfilled(c, act(route,0), acts.get(0), act(route,1), 20));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, act(route,1), acts.get(0), route.getEnd(), 40));
//insert pickup at 0
c.setRelatedActivityContext(new ActivityContext());
c.getRelatedActivityContext().setArrivalTime(20);
c.getRelatedActivityContext().setEndTime(30);
c.getRelatedActivityContext().setInsertionIndex(0);
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, acts.get(0), acts.get(1), act(route,0), 30));
Assert.assertEquals(HardActivityConstraint.ConstraintsStatus.FULFILLED, constraint.fulfilled(c, act(route,0), acts.get(1), act(route,1), 30));
}
private TourActivity act(VehicleRoute route, int index){
return route.getActivities().get(index);
}
@Test
@ -94,7 +150,7 @@ public class MaxTimeInVehicleConstraintTest {
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(route,d2,v,route.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(d2);
c.getAssociatedActivities().add(acts.get(0));
@ -116,7 +172,7 @@ public class MaxTimeInVehicleConstraintTest {
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(route),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(route,d2,v,route.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(d2);
c.getAssociatedActivities().add(acts.get(0));
@ -142,9 +198,9 @@ public class MaxTimeInVehicleConstraintTest {
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(shipment);
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0));
c.getAssociatedActivities().add(acts.get(1));
@ -169,8 +225,8 @@ public class MaxTimeInVehicleConstraintTest {
// stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
//
// MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(), vrp.getActivityCosts(), latestStartId, stateManager);
// JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
// List<AbstractActivity> acts = vrp.getActivities(shipment);
// JobInsertionContext c = new JobInsertionContext(r,s1,v,r.getDriver(),0.);
// List<AbstractActivity> acts = vrp.getActivities(s1);
// c.getAssociatedActivities().add(acts.get(0));
// c.getAssociatedActivities().add(acts.get(1));
//
@ -192,14 +248,14 @@ public class MaxTimeInVehicleConstraintTest {
StateId latestStartId = stateManager.createStateId("latest-start-id");
Map<String,Double> maxTimes = new HashMap<>();
maxTimes.put("shipment",25d);
maxTimes.put("s1",25d);
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(shipment);
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0));
c.getAssociatedActivities().add(acts.get(1));
@ -223,14 +279,14 @@ public class MaxTimeInVehicleConstraintTest {
StateId latestStartId = stateManager.createStateId("latest-start-id");
Map<String,Double> maxTimes = new HashMap<>();
maxTimes.put("shipment",25d);
maxTimes.put("s1",25d);
UpdateMaxTimeInVehicle updater = new UpdateMaxTimeInVehicle(stateManager,latestStartId,vrp.getTransportCosts(), vrp.getActivityCosts());
stateManager.addStateUpdater(updater);
stateManager.informInsertionStarts(Arrays.asList(r),new ArrayList<Job>());
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager);
JobInsertionContext c = new JobInsertionContext(r,shipment,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(shipment);
MaxTimeInVehicleConstraint constraint = new MaxTimeInVehicleConstraint(vrp.getTransportCosts(),vrp.getActivityCosts() , latestStartId, stateManager, vrp);
JobInsertionContext c = new JobInsertionContext(r, s1,v,r.getDriver(),0.);
List<AbstractActivity> acts = vrp.getActivities(s1);
c.getAssociatedActivities().add(acts.get(0));
c.getAssociatedActivities().add(acts.get(1));

View file

@ -0,0 +1,357 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.problem.constraint;
import com.graphhopper.jsprit.core.algorithm.state.StateId;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
import com.graphhopper.jsprit.core.problem.job.Delivery;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Pickup;
import com.graphhopper.jsprit.core.problem.job.Shipment;
import com.graphhopper.jsprit.core.problem.misc.ActivityContext;
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
import com.graphhopper.jsprit.core.problem.solution.route.activity.Start;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.util.ManhattanCosts;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.*;
import static org.mockito.Mockito.mock;
/**
* Created by schroeder on 18/05/16.
*/
public class VehicleDependentTraveledDistanceTest {
StateManager stateManager;
VehicleRoute route;
StateId traveledDistanceId;
Vehicle vehicle;
Vehicle vehicle2;
VehicleRoutingProblem vrp;
Delivery d1,d2,newDelivery;
Pickup pickup;
Shipment s1;
Map<Vehicle,Double> maxDistanceMap;
@Before
public void doBefore(){
vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
vehicle2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(Location.newInstance(10,10)).build();
maxDistanceMap = new HashMap<>();
maxDistanceMap.put(vehicle,200d);
maxDistanceMap.put(vehicle2,200d);
d1 = Delivery.Builder.newInstance("d1").setLocation(Location.newInstance(10,10)).build();
d2 = Delivery.Builder.newInstance("d2").setLocation(Location.newInstance(20,15)).build();
pickup = Pickup.Builder.newInstance("pickup").setLocation(Location.newInstance(50,50)).build();
s1 = Shipment.Builder.newInstance("s1").setPickupLocation(Location.newInstance(35,30))
.setDeliveryLocation(Location.newInstance(20,25)).build();
newDelivery = Delivery.Builder.newInstance("new").setLocation(Location.newInstance(-10,10)).build();
vrp = VehicleRoutingProblem.Builder.newInstance()
.setRoutingCost(new ManhattanCosts()).addVehicle(vehicle).addVehicle(vehicle2)
.addJob(d1).addJob(d2).addJob(s1).addJob(pickup).addJob(newDelivery).build();
route = VehicleRoute.Builder.newInstance(vehicle).setJobActivityFactory(vrp.getJobActivityFactory())
.addDelivery(d1).addDelivery(d2).addPickup(s1).addPickup(pickup).addDelivery(s1).build();
stateManager = new StateManager(vrp);
traveledDistanceId = stateManager.createStateId("traveledDistance");
com.graphhopper.jsprit.core.algorithm.state.VehicleDependentTraveledDistance traveledDistance =
new com.graphhopper.jsprit.core.algorithm.state.VehicleDependentTraveledDistance(new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return new ManhattanCosts().getDistance(from,to,departureTime,vehicle);
}
},stateManager,traveledDistanceId,Arrays.asList(vehicle,vehicle2));
stateManager.addStateUpdater(traveledDistance);
stateManager.informInsertionStarts(Arrays.asList(route), Collections.<Job>emptyList());
}
@Test
public void whenEndLocationIsSet_constraintShouldWork(){
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0))
.setEndLocation(Location.newInstance(10,0)).build();
Pickup pickup = Pickup.Builder.newInstance("pickup").setLocation(Location.newInstance(10,0)).build();
vrp = VehicleRoutingProblem.Builder.newInstance().addVehicle(vehicle).addJob(pickup).build();
route = VehicleRoute.emptyRoute();
maxDistanceMap = new HashMap<>();
maxDistanceMap.put(vehicle,5d);
MaxDistanceConstraint maxDistanceConstraint =
new MaxDistanceConstraint(new StateManager(vrp), traveledDistanceId, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
}
},maxDistanceMap);
JobInsertionContext context = new JobInsertionContext(route,pickup,vehicle,null,0);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
new Start(vehicle.getStartLocation(),0,Double.MAX_VALUE),vrp.getActivities(pickup).get(0),
new End(vehicle.getEndLocation(),0,Double.MAX_VALUE),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
}
/*
vehicle: 200.0
vehicle (max distance): 200.0
vehicle2: 160.0
vehicle2 (max distance): 180.0
*/
@Test
public void insertNewInVehicleShouldFail(){
MaxDistanceConstraint maxDistanceConstraint =
new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
}
},maxDistanceMap);
JobInsertionContext context = new JobInsertionContext(route,newDelivery,vehicle,null,0);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,route.getStart(),newAct(),act(0),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(0),newAct(),act(1),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(1),newAct(),act(2),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(2),newAct(),act(3),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(3),newAct(),act(4),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(4),newAct(),route.getEnd(),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
}
@Test
public void insertNewInVehicle2ShouldBeCorrect(){
//current distance vehicle2: 160 allowed: 200
MaxDistanceConstraint maxDistanceConstraint =
new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
}
},maxDistanceMap);
JobInsertionContext context = new JobInsertionContext(route,newDelivery,vehicle2,null,0);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,route.getStart(),newAct(),act(0),0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
//additional distance: 20+35-15=40
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(0),newAct(),act(1),0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
//additional distance: 35+65-30=70
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(1),newAct(),act(2),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
//additional distance: 65+100-35
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(2),newAct(),act(3),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
//additional distance: 100+45-55
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(3),newAct(),act(4),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED));
//additional distance: 45+20-25
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(4),newAct(),route.getEnd(),0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
}
private TourActivity act(int i) {
return route.getActivities().get(i);
}
private TourActivity newAct(){
return vrp.getActivities(newDelivery).get(0);
}
@Test
public void traveledDistanceShouldBeCorrect(){
Assert.assertEquals(20d,stateManager.getActivityState(route.getActivities().get(0),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(35d,stateManager.getActivityState(route.getActivities().get(1),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(65d,stateManager.getActivityState(route.getActivities().get(2),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(100d,stateManager.getActivityState(route.getActivities().get(3),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(155d,stateManager.getActivityState(route.getActivities().get(4),vehicle,traveledDistanceId,Double.class),0.01);
}
@Test
public void traveledDistanceWithVehicle2ShouldBeCorrect(){
Assert.assertEquals(0d,stateManager.getActivityState(route.getActivities().get(0),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(15d,stateManager.getActivityState(route.getActivities().get(1),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(45d,stateManager.getActivityState(route.getActivities().get(2),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(80d,stateManager.getActivityState(route.getActivities().get(3),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(135d,stateManager.getActivityState(route.getActivities().get(4),vehicle2,traveledDistanceId,Double.class),0.01);
}
@Test
public void distanceOfShipmentInRoute(){
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle,traveledDistanceId, Double.class);
double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle, traveledDistanceId, Double.class);
Assert.assertEquals(90d,traveledDistanceBeforeDelivery-traveledDistanceBeforePickup,0.01);
}
@Test
public void distanceOfShipmentInRouteVehicle2(){
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle2,traveledDistanceId, Double.class);
double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle2, traveledDistanceId, Double.class);
Assert.assertEquals(90d,traveledDistanceBeforeDelivery-traveledDistanceBeforePickup,0.01);
}
@Test
public void distanceOfPickupInRoute(){
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3), vehicle, traveledDistanceId, Double.class);
double total = stateManager.getRouteState(route, vehicle,traveledDistanceId, Double.class);
Assert.assertEquals(100d,total-traveledDistanceBeforePickup,0.01);
}
@Test
public void distanceOfPickupInRouteVehicle2(){
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3), vehicle2, traveledDistanceId, Double.class);
double total = stateManager.getRouteState(route, vehicle2,traveledDistanceId, Double.class);
Assert.assertEquals(80d,total-traveledDistanceBeforePickup,0.01);
}
@Test
public void distanceToTravelShouldBeCorrect(){
double total = stateManager.getRouteState(route, vehicle, traveledDistanceId, Double.class);
Assert.assertEquals(180d,total - stateManager.getActivityState(route.getActivities().get(0),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(165d, total - stateManager.getActivityState(route.getActivities().get(1), vehicle, traveledDistanceId, Double.class), 0.01);
Assert.assertEquals(135d,total - stateManager.getActivityState(route.getActivities().get(2),vehicle,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(100d, total - stateManager.getActivityState(route.getActivities().get(3), vehicle, traveledDistanceId, Double.class), 0.01);
Assert.assertEquals(45d, total - stateManager.getActivityState(route.getActivities().get(4), vehicle, traveledDistanceId, Double.class), 0.01);
}
@Test
public void distanceToTravelShouldBeCorrectVehicle2(){
double total = stateManager.getRouteState(route, vehicle2, traveledDistanceId, Double.class);
Assert.assertEquals(160d,total - stateManager.getActivityState(route.getActivities().get(0),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(145d, total - stateManager.getActivityState(route.getActivities().get(1), vehicle2, traveledDistanceId, Double.class), 0.01);
Assert.assertEquals(115d,total - stateManager.getActivityState(route.getActivities().get(2),vehicle2,traveledDistanceId,Double.class),0.01);
Assert.assertEquals(80d, total - stateManager.getActivityState(route.getActivities().get(3), vehicle2, traveledDistanceId, Double.class), 0.01);
Assert.assertEquals(25d, total - stateManager.getActivityState(route.getActivities().get(4), vehicle2, traveledDistanceId, Double.class), 0.01);
}
@Test
public void whenAddingDeliverShipment_constraintShouldWork() {
Shipment shipment = Shipment.Builder.newInstance("s")
.setPickupLocation(Location.newInstance(0, 3))
.setDeliveryLocation(Location.newInstance(4, 0))
.build();
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v")
.setStartLocation(Location.newInstance(0, 0))
.build();
final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
.addJob(shipment)
.addVehicle(vehicle)
.build();
VehicleRoute route = VehicleRoute.emptyRoute();
JobInsertionContext context = new JobInsertionContext(route, shipment, vehicle, null, 0);
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(0));
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(1));
maxDistanceMap = new HashMap<>();
maxDistanceMap.put(vehicle,12d);
StateManager stateManager = new StateManager(vrp);
MaxDistanceConstraint maxDistanceConstraint =
new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
}
},maxDistanceMap);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
new Start(vehicle.getStartLocation(), 0, Double.MAX_VALUE),
vrp.getActivities(shipment).get(0),
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
ActivityContext pickupContext = new ActivityContext();
pickupContext.setArrivalTime(3);
pickupContext.setEndTime(3);
pickupContext.setInsertionIndex(0);
context.setRelatedActivityContext(pickupContext);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
vrp.getActivities(shipment).get(0),
vrp.getActivities(shipment).get(1),
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
3).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
}
@Test
public void whenAddingDeliverShipmentWithVehDiffStartEndLocs_constraintShouldWork() {
Shipment shipment = Shipment.Builder.newInstance("s")
.setPickupLocation(Location.newInstance(0, 1))
.setDeliveryLocation(Location.newInstance(4, 1))
.build();
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v")
.setStartLocation(Location.newInstance(0, 0))
.setEndLocation(Location.newInstance(0, 4))
.build();
final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
.addJob(shipment)
.addVehicle(vehicle)
.build();
VehicleRoute route = VehicleRoute.emptyRoute();
JobInsertionContext context = new JobInsertionContext(route, shipment, vehicle, null, 0);
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(0));
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(1));
maxDistanceMap = new HashMap<>();
maxDistanceMap.put(vehicle,10d);
StateManager stateManager = new StateManager(vrp);
MaxDistanceConstraint maxDistanceConstraint =
new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
}
},maxDistanceMap);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
new Start(vehicle.getStartLocation(), 0, Double.MAX_VALUE),
vrp.getActivities(shipment).get(0),
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
ActivityContext pickupContext = new ActivityContext();
pickupContext.setArrivalTime(1);
pickupContext.setEndTime(1);
pickupContext.setInsertionIndex(0);
context.setRelatedActivityContext(pickupContext);
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
vrp.getActivities(shipment).get(0),
vrp.getActivities(shipment).get(1),
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
1).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
}
}

View file

@ -17,11 +17,18 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import com.graphhopper.jsprit.core.problem.Location;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.*;
import com.graphhopper.jsprit.core.problem.Location;
public class DeliveryTest {
@ -119,4 +126,16 @@ public class DeliveryTest {
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheJob() {
Delivery one = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setUserData(new HashMap<String, Object>()).build();
Delivery two = Delivery.Builder.newInstance("s2").setLocation(Location.newInstance("loc")).setUserData(42)
.build();
Delivery three = Delivery.Builder.newInstance("s3").setLocation(Location.newInstance("loc")).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
}

View file

@ -17,11 +17,18 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import com.graphhopper.jsprit.core.problem.Location;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.*;
import com.graphhopper.jsprit.core.problem.Location;
public class PickupTest {
@ -105,6 +112,18 @@ public class PickupTest {
Assert.assertEquals(2, s.getPriority());
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheJob() {
Pickup one = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setUserData(new HashMap<String, Object>()).build();
Pickup two = Pickup.Builder.newInstance("s2").setLocation(Location.newInstance("loc")).setUserData(42).build();
Pickup three = Pickup.Builder.newInstance("s3").setLocation(Location.newInstance("loc")).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
@Test(expected = UnsupportedOperationException.class)
public void whenAddingMaxTimeInVehicle_itShouldThrowEx(){
Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc"))

View file

@ -17,17 +17,25 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.*;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
public class ServiceTest {
@ -53,7 +61,7 @@ public class ServiceTest {
Service one = Service.Builder.newInstance("service").addSizeDimension(0, 10).setLocation(Location.newInstance("foo")).build();
Service two = Service.Builder.newInstance("service").addSizeDimension(0, 10).setLocation(Location.newInstance("fo")).build();
serviceSet.add(one);
// assertTrue(serviceSet.contains(two));
// assertTrue(serviceSet.contains(two));
serviceSet.remove(two);
assertTrue(serviceSet.isEmpty());
}
@ -250,6 +258,13 @@ public class ServiceTest {
Assert.assertEquals(3, s.getPriority());
}
@Test
public void whenSettingPriorities_itShouldBeSetCorrectly3() {
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setPriority(10).build();
Assert.assertEquals(10, s.getPriority());
}
@Test
public void whenNotSettingPriorities_defaultShouldBe2(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
@ -285,4 +300,17 @@ public class ServiceTest {
Assert.assertEquals(Double.MAX_VALUE, s.getMaxTimeInVehicle(),0.001);
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheJob() {
Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
.setUserData(new HashMap<String, Object>()).build();
Service two = Service.Builder.newInstance("s2").setLocation(Location.newInstance("loc")).setUserData(42)
.build();
Service three = Service.Builder.newInstance("s3").setLocation(Location.newInstance("loc")).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
}

View file

@ -17,16 +17,25 @@
*/
package com.graphhopper.jsprit.core.problem.job;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.util.Coordinate;
import com.graphhopper.jsprit.core.util.TestUtils;
import org.junit.Assert;
import org.junit.Test;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsCollectionContaining.hasItem;
import static org.junit.Assert.*;
public class ShipmentTest {
@ -401,6 +410,14 @@ public class ShipmentTest {
Assert.assertEquals(3, s.getPriority());
}
@Test
public void whenSettingPriorities_itShouldBeSetCorrectly3() {
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc"))
.setPriority(10).build();
Assert.assertEquals(10, s.getPriority());
}
@Test
public void whenNotSettingPriorities_defaultShouldBe2(){
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
@ -425,6 +442,19 @@ public class ShipmentTest {
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheJob() {
Shipment one = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc")).setUserData(new HashMap<String, Object>()).build();
Shipment two = Shipment.Builder.newInstance("s2").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc")).setUserData(42).build();
Shipment three = Shipment.Builder.newInstance("s3").setPickupLocation(Location.newInstance("loc"))
.setDeliveryLocation(Location.newInstance("loc")).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
@Test
public void whenAddingMaxTimeInVehicle_itShouldBeSet(){
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")).setDeliveryLocation(Location.newInstance("loc"))

View file

@ -18,12 +18,20 @@
package com.graphhopper.jsprit.core.problem.vehicle;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.job.Break;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import org.junit.Test;
import static org.junit.Assert.*;
public class VehicleImplTest {
@ -39,7 +47,7 @@ public class VehicleImplTest {
@Test
public void whenAddingDriverBreak_itShouldBeAddedCorrectly() {
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build();
Break aBreak = (Break) Break.Builder.newInstance("break").setTimeWindow(TimeWindow.newInstance(100, 200)).setServiceTime(30).build();
Break aBreak = Break.Builder.newInstance("break").setTimeWindow(TimeWindow.newInstance(100, 200)).setServiceTime(30).build();
Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("start"))
.setType(type1).setEndLocation(Location.newInstance("start"))
.setBreak(aBreak).build();
@ -237,5 +245,19 @@ public class VehicleImplTest {
assertFalse(v.getSkills().containsSkill("ScrewDriver"));
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheVehicle() {
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build();
Vehicle one = VehicleImpl.Builder.newInstance("v").setType(type1)
.setStartLocation(Location.newInstance("start")).setUserData(new HashMap<String, Object>()).build();
Vehicle two = VehicleImpl.Builder.newInstance("v").setType(type1)
.setStartLocation(Location.newInstance("start")).setUserData(42).build();
Vehicle three = VehicleImpl.Builder.newInstance("v").setType(type1)
.setStartLocation(Location.newInstance("start")).build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
}

View file

@ -17,9 +17,15 @@
*/
package com.graphhopper.jsprit.core.problem.vehicle;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
public class VehicleTypeImplTest {
@ -152,4 +158,15 @@ public class VehicleTypeImplTest {
}
@Test
public void whenSettingUserData_itIsAssociatedWithTheVehicleType() {
VehicleType one = VehicleTypeImpl.Builder.newInstance("type").setUserData(new HashMap<String, Object>())
.build();
VehicleType two = VehicleTypeImpl.Builder.newInstance("type").setUserData(42).build();
VehicleType three = VehicleTypeImpl.Builder.newInstance("type").build();
assertTrue(one.getUserData() instanceof Map);
assertEquals(42, two.getUserData());
assertNull(three.getUserData());
}
}

View file

@ -40,6 +40,7 @@ public class FastVehicleRoutingTransportCostsMatrixTest {
assertEquals(2., matrix.getDistance(2, 1), 0.1);
}
@Test
public void whenAddingDistanceToAsymmetricMatrix_itShouldReturnCorrectValues() {
FastVehicleRoutingTransportCostsMatrix.Builder matrixBuilder = FastVehicleRoutingTransportCostsMatrix.Builder.newInstance(3, false);
@ -62,6 +63,18 @@ public class FastVehicleRoutingTransportCostsMatrixTest {
assertEquals(2., matrix.getTransportTime(loc(2), loc(1), 0.0, null, null), 0.1);
}
@Test
public void whenAddingTimeAndDistanceToSymmetricMatrix_itShouldReturnCorrectValues2() {
FastVehicleRoutingTransportCostsMatrix.Builder matrixBuilder = FastVehicleRoutingTransportCostsMatrix.Builder.newInstance(3, true);
matrixBuilder.addTransportTimeAndDistance(1, 2, 2.,100.);
FastVehicleRoutingTransportCostsMatrix matrix = matrixBuilder.build();
assertEquals(2., matrix.getTransportTime(loc(1), loc(2), 0.0, null, null), 0.1);
assertEquals(2., matrix.getTransportTime(loc(2), loc(1), 0.0, null, null), 0.1);
assertEquals(100., matrix.getDistance(loc(1), loc(2), 0.0, null), 0.1);
assertEquals(100., matrix.getDistance(loc(2), loc(1), 0.0, null), 0.1);
}
@Test
public void whenAddingTimeToAsymmetricMatrix_itShouldReturnCorrectValues() {
FastVehicleRoutingTransportCostsMatrix.Builder matrixBuilder = FastVehicleRoutingTransportCostsMatrix.Builder.newInstance(3, false);

View file

@ -0,0 +1,156 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.util;
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
import com.graphhopper.jsprit.core.algorithm.box.Jsprit;
import com.graphhopper.jsprit.core.algorithm.state.StateId;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.constraint.MaxDistanceConstraint;
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
import com.graphhopper.jsprit.core.problem.job.Service;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleType;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
import org.apache.commons.math3.stat.Frequency;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Created by schroeder on 06/02/17.
*/
public class UnassignedJobReasonTrackerTest {
Vehicle vehicle;
@Before
public void doBefore() {
VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(0, 1);
VehicleType vehicleType = vehicleTypeBuilder.build();
VehicleImpl.Builder vehicleBuilder = VehicleImpl.Builder.newInstance("vehicle");
vehicleBuilder.setStartLocation(Location.newInstance(10, 10));
vehicleBuilder.setType(vehicleType);
vehicleBuilder.setEarliestStart(0).setLatestArrival(100);
vehicle = vehicleBuilder.build();
}
@Test
public void shouldReturnCorrectCapacityReasonCode() {
Service service = Service.Builder.newInstance("1").addSizeDimension(0, 5).setLocation(Location.newInstance(5, 7)).build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service)
.build();
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
vra.addListener(reasonTracker);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
Assert.assertEquals(1, solution.getUnassignedJobs().size());
Assert.assertEquals(3, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
}
@Test
public void shouldReturnCorrectSkillReasonCode() {
Service service = Service.Builder.newInstance("1").addSizeDimension(0, 1).addRequiredSkill("ice").setLocation(Location.newInstance(5, 7)).build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service)
.build();
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
vra.addListener(reasonTracker);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
Assert.assertEquals(1, solution.getUnassignedJobs().size());
Assert.assertEquals(1, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
}
@Test
public void shouldReturnCorrectTWReasonCode() {
Service service = Service.Builder.newInstance("1").addSizeDimension(0, 1).setTimeWindow(TimeWindow.newInstance(110, 200)).setLocation(Location.newInstance(5, 7)).build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service)
.build();
VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
vra.addListener(reasonTracker);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
Assert.assertEquals(1, solution.getUnassignedJobs().size());
Assert.assertEquals(2, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
}
@Test
public void shouldReturnCorrectMaxDistanceReasonCode() {
Service service = Service.Builder.newInstance("1").setLocation(Location.newInstance(51, 0)).build();
Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0, 0)).build();
final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service).build();
StateManager stateManager = new StateManager(vrp);
ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
StateId maxDistance = stateManager.createStateId("max-distance");
Map<Vehicle, Double> distMap = new HashMap<>();
distMap.put(vehicle, 100d);
MaxDistanceConstraint distanceConstraint = new MaxDistanceConstraint(stateManager, maxDistance, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportCost(from, to, departureTime, null, vehicle);
}
}, distMap);
constraintManager.addConstraint(distanceConstraint, ConstraintManager.Priority.CRITICAL);
VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setStateAndConstraintManager(stateManager, constraintManager)
.buildAlgorithm();
UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
vra.addListener(reasonTracker);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
Assert.assertEquals(1, solution.getUnassignedJobs().size());
Assert.assertEquals(4, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
}
@Test
public void testFreq() {
Frequency frequency = new Frequency();
frequency.addValue("VehicleDependentTimeWindowHardActivityConstraint");
frequency.addValue("b");
frequency.addValue("VehicleDependentTimeWindowHardActivityConstraint");
Iterator<Map.Entry<Comparable<?>, Long>> entryIterator = frequency.entrySetIterator();
while (entryIterator.hasNext()) {
Map.Entry<Comparable<?>, Long> e = entryIterator.next();
System.out.println(e.getKey().toString() + " " + e.getValue());
}
}
}

View file

@ -0,0 +1,56 @@
2 4 50 4
0 2000
1 37 52 0 7 1 4 1 2 4 8
2 49 49 0 30 1 4 1 2 4 8
3 52 64 0 16 1 4 1 2 4 8
4 20 26 0 9 1 4 1 2 4 8
5 40 30 0 21 1 4 1 2 4 8
6 21 47 0 15 1 4 1 2 4 8
7 17 63 0 19 1 4 1 2 4 8
8 31 62 0 23 1 4 1 2 4 8
9 52 33 0 11 1 4 1 2 4 8
10 51 21 0 5 1 4 1 2 4 8
11 42 41 0 19 1 4 1 2 4 8
12 31 32 0 29 1 4 1 2 4 8
13 5 25 0 23 1 4 1 2 4 8
14 12 42 0 21 1 4 1 2 4 8
15 36 16 0 10 1 4 1 2 4 8
16 52 41 0 15 1 4 1 2 4 8
17 27 23 0 3 1 4 1 2 4 8
18 17 33 0 41 1 4 1 2 4 8
19 13 13 0 9 1 4 1 2 4 8
20 57 58 0 28 1 4 1 2 4 8
21 62 42 0 8 1 4 1 2 4 8
22 42 57 0 8 1 4 1 2 4 8
23 16 57 0 16 1 4 1 2 4 8
24 8 52 0 10 1 4 1 2 4 8
25 7 38 0 28 1 4 1 2 4 8
26 27 68 0 7 1 4 1 2 4 8
27 30 48 0 15 1 4 1 2 4 8
28 43 67 0 14 1 4 1 2 4 8
29 58 48 0 6 1 4 1 2 4 8
30 58 27 0 19 1 4 1 2 4 8
31 37 69 0 11 1 4 1 2 4 8
32 38 46 0 12 1 4 1 2 4 8
33 46 10 0 23 1 4 1 2 4 8
34 61 33 0 26 1 4 1 2 4 8
35 62 63 0 17 1 4 1 2 4 8
36 63 69 0 6 1 4 1 2 4 8
37 32 22 0 9 1 4 1 2 4 8
38 45 35 0 15 1 4 1 2 4 8
39 59 15 0 14 1 4 1 2 4 8
40 5 6 0 7 1 4 1 2 4 8
41 10 17 0 27 1 4 1 2 4 8
42 21 10 0 13 1 4 1 2 4 8
43 5 64 0 11 1 4 1 2 4 8
44 30 15 0 16 1 4 1 2 4 8
45 39 10 0 10 1 4 1 2 4 8
46 32 39 0 5 1 4 1 2 4 8
47 25 32 0 25 1 4 1 2 4 8
48 25 55 0 17 1 4 1 2 4 8
49 48 28 0 18 1 4 1 2 4 8
50 56 37 0 10 1 4 1 2 4 8
51 20 20 0 0 0 0
52 30 40 0 0 0 0
53 50 30 0 0 0 0
54 60 50 0 0 0 0

View file

@ -20,7 +20,7 @@
<parent>
<groupId>com.graphhopper</groupId>
<artifactId>jsprit</artifactId>
<version>1.6.3-SNAPSHOT</version>
<version>1.7.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View file

@ -20,7 +20,6 @@ package com.graphhopper.jsprit.examples;
import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsRecorder;
import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsViewer;
import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder;
import com.graphhopper.jsprit.core.algorithm.SearchStrategy;
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
@ -116,17 +115,18 @@ public class BuildAlgorithmFromScratch {
final VehicleRoutingProblem vrp = vrpBuilder.build();
VehicleRoutingAlgorithm vra = createAlgorithm(vrp);
vra.setMaxIterations(100);
vra.setMaxIterations(2000);
AlgorithmEventsRecorder eventsRecorder = new AlgorithmEventsRecorder(vrp, "output/events.dgs.gz");
eventsRecorder.setRecordingRange(90, 100);
vra.addListener(eventsRecorder);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE);
AlgorithmEventsViewer viewer = new AlgorithmEventsViewer();
viewer.setRuinDelay(3);
viewer.setRecreationDelay(1);
viewer.display("output/events.dgs.gz");
// AlgorithmEventsViewer viewer = new AlgorithmEventsViewer();
// viewer.setRuinDelay(3);
// viewer.setRecreationDelay(1);
// viewer.display("output/events.dgs.gz");
}
@ -146,10 +146,11 @@ public class BuildAlgorithmFromScratch {
//regret insertion
InsertionBuilder iBuilder = new InsertionBuilder(vrp, fleetManager, stateManager, constraintManager);
iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET);
iBuilder.setFastRegret(true);
RegretInsertionFast regret = (RegretInsertionFast) iBuilder.build();
DefaultScorer scoringFunction = new DefaultScorer(vrp);
scoringFunction.setDepotDistanceParam(0.2);
scoringFunction.setTimeWindowParam(-.2);
scoringFunction.setDepotDistanceParam(0.0);
scoringFunction.setTimeWindowParam(0.0);
regret.setScoringFunction(scoringFunction);
/*

View file

@ -20,7 +20,7 @@
<parent>
<groupId>com.graphhopper</groupId>
<artifactId>jsprit</artifactId>
<version>1.6.3-SNAPSHOT</version>
<version>1.7.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View file

@ -23,7 +23,7 @@
<parent>
<groupId>com.graphhopper</groupId>
<artifactId>jsprit</artifactId>
<version>1.6.3-SNAPSHOT</version>
<version>1.7.3-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View file

@ -701,7 +701,8 @@ public class VrpXMLReader {
List<HierarchicalConfiguration> breakTWConfigs = vehicleConfig.configurationsAt("breaks.timeWindows.timeWindow");
if (!breakTWConfigs.isEmpty()) {
String breakDurationString = vehicleConfig.getString("breaks.duration");
Break.Builder current_break = Break.Builder.newInstance(vehicleId);
String id = vehicleConfig.getString("breaks.id");
Break.Builder current_break = Break.Builder.newInstance(id);
current_break.setServiceTime(Double.parseDouble(breakDurationString));
for (HierarchicalConfiguration twConfig : breakTWConfigs) {
current_break.addTimeWindow(TimeWindow.newInstance(twConfig.getDouble("start"), twConfig.getDouble("end")));

View file

@ -41,9 +41,7 @@ import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.io.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -94,8 +92,36 @@ public class VrpXMLWriter {
public void write(String filename) {
if (!filename.endsWith(".xml")) filename += ".xml";
log.info("write vrp: " + filename);
XMLConf xmlConfig = new XMLConf();
XMLConf xmlConfig = createXMLConfiguration();
try {
xmlConfig.setFileName(filename);
Writer out = new FileWriter(filename);
XMLSerializer serializer = new XMLSerializer(out, createOutputFormat());
serializer.serialize(xmlConfig.getDocument());
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public OutputStream write() {
XMLConf xmlConfig = createXMLConfiguration();
OutputStream out = new ByteArrayOutputStream();
try {
XMLSerializer serializer = new XMLSerializer(out, createOutputFormat());
serializer.serialize(xmlConfig.getDocument());
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
return out;
}
private XMLConf createXMLConfiguration() {
XMLConf xmlConfig = new XMLConf();
xmlConfig.setRootElementName("problem");
xmlConfig.setAttributeSplittingDisabled(true);
xmlConfig.setDelimiterParsingDisabled(true);
@ -123,10 +149,6 @@ public class VrpXMLWriter {
writeSolutions(xmlConfig);
OutputFormat format = new OutputFormat();
format.setIndenting(true);
format.setIndent(5);
try {
Document document = xmlConfig.createDoc();
@ -138,17 +160,14 @@ public class VrpXMLWriter {
} catch (ConfigurationException e) {
throw new RuntimeException(e);
}
try {
Writer out = new FileWriter(filename);
XMLSerializer serializer = new XMLSerializer(out, format);
serializer.serialize(xmlConfig.getDocument());
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
return xmlConfig;
}
private OutputFormat createOutputFormat() {
OutputFormat format = new OutputFormat();
format.setIndenting(true);
format.setIndent(5);
return format;
}
private void writeInitialRoutes(XMLConf xmlConfig) {
@ -203,12 +222,12 @@ public class VrpXMLWriter {
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ")[@type]", act.getName());
if (act instanceof TourActivity.JobActivity) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (job instanceof Service) {
if (job instanceof Break) {
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").breakId", job.getId());
} else if (job instanceof Service) {
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").serviceId", job.getId());
} else if (job instanceof Shipment) {
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").shipmentId", job.getId());
} else if (job instanceof Break) {
xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").breakId", job.getId());
} else {
throw new IllegalStateException("cannot write solution correctly since job-type is not know. make sure you use either service or shipment, or another writer");
}

View file

@ -395,6 +395,7 @@
</xs:complexType>
</xs:element>
<xs:element name="duration" type="xs:double" minOccurs="1" maxOccurs="1" default="0.0"/>
<xs:element name="id" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>

View file

@ -31,9 +31,11 @@ import com.graphhopper.jsprit.core.util.Coordinate;
import com.graphhopper.jsprit.core.util.Solutions;
import com.graphhopper.jsprit.io.util.TestUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@ -42,77 +44,15 @@ import static org.junit.Assert.*;
public class VrpXMLWriterTest {
private String infileName;
@Before
public void doBefore() {
infileName = "src/test/resources/infiniteWriterV2Test.xml";
}
@Test
public void whenWritingInfiniteVrp_itWritesCorrectly() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
builder.setFleetSize(VehicleRoutingProblem.FleetSize.INFINITE);
VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("myVehicle").setStartLocation(TestUtils.loc("loc")).setType(type).build();
builder.addVehicle(vehicle);
VehicleRoutingProblem vrp = builder.build();
new VrpXMLWriter(vrp, null).write(infileName);
}
@Test
public void whenWritingFiniteVrp_itWritesCorrectly() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
builder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE);
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build();
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build();
builder.addVehicle(v1);
builder.addVehicle(v2);
VehicleRoutingProblem vrp = builder.build();
new VrpXMLWriter(vrp, null).write(infileName);
}
@Test
public void t() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
builder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE);
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build();
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build();
builder.addVehicle(v1);
builder.addVehicle(v2);
VehicleRoutingProblem vrp = builder.build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
}
@Test
public void whenWritingServices_itWritesThemCorrectly() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build();
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build();
builder.addVehicle(v1);
builder.addVehicle(v2);
VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls();
Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build();
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build();
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
assertEquals(2, readVrp.getJobs().size());
Service s1_read = (Service) vrp.getJobs().get("1");
@ -128,11 +68,7 @@ public class VrpXMLWriterTest {
Service s1 = Service.Builder.newInstance("1").setName("cleaning").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build();
VehicleRoutingProblem vrp = builder.addJob(s1).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Service s1_read = (Service) readVrp.getJobs().get("1");
assertTrue(s1_read.getName().equals("cleaning"));
}
@ -146,11 +82,7 @@ public class VrpXMLWriterTest {
.setDeliveryLocation(TestUtils.loc("del")).build();
VehicleRoutingProblem vrp = builder.addJob(s1).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Shipment s1_read = (Shipment) readVrp.getJobs().get("1");
assertTrue(s1_read.getName().equals("cleaning"));
Assert.assertEquals(1, s1_read.getPickupLocation().getIndex());
@ -167,32 +99,20 @@ public class VrpXMLWriterTest {
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build();
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
assertEquals(2, readVrp.getJobs().size());
Service s1_read = (Service) vrp.getJobs().get("1");
Assert.assertEquals(2, s1_read.getSize().getNuOfDimensions());
Assert.assertEquals(20, s1_read.getSize().get(0));
Assert.assertEquals(200, s1_read.getSize().get(1));
assertEquals(2, s1_read.getSize().getNuOfDimensions());
assertEquals(20, s1_read.getSize().get(0));
assertEquals(200, s1_read.getSize().get(1));
}
@Test
public void whenWritingShipments_readingThemAgainMustReturnTheWrittenLocationIdsOfS1() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build();
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build();
builder.addVehicle(v1);
builder.addVehicle(v2);
VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls();
Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10)
.setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build())
@ -205,29 +125,17 @@ public class VrpXMLWriterTest {
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
assertEquals(2, readVrp.getJobs().size());
Assert.assertEquals("pickLoc", ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getId());
Assert.assertEquals("delLoc", ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getId());
assertEquals("pickLoc", ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getId());
assertEquals("delLoc", ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getId());
}
@Test
public void whenWritingShipments_readingThemAgainMustReturnTheWrittenPickupTimeWindowsOfS1() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build();
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build();
builder.addVehicle(v1);
builder.addVehicle(v2);
VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls();
Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10)
.setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build())
@ -240,30 +148,18 @@ public class VrpXMLWriterTest {
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
assertEquals(2, readVrp.getJobs().size());
Assert.assertEquals(1.0, ((Shipment) readVrp.getJobs().get("1")).getPickupTimeWindow().getStart(), 0.01);
Assert.assertEquals(2.0, ((Shipment) readVrp.getJobs().get("1")).getPickupTimeWindow().getEnd(), 0.01);
assertEquals(1.0, ((Shipment) readVrp.getJobs().get("1")).getPickupTimeWindow().getStart(), 0.01);
assertEquals(2.0, ((Shipment) readVrp.getJobs().get("1")).getPickupTimeWindow().getEnd(), 0.01);
}
@Test
public void whenWritingShipments_readingThemAgainMustReturnTheWrittenDeliveryTimeWindowsOfS1() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build();
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build();
builder.addVehicle(v1);
builder.addVehicle(v2);
VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls();
Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10)
.setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build())
@ -276,29 +172,17 @@ public class VrpXMLWriterTest {
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
assertEquals(2, readVrp.getJobs().size());
Assert.assertEquals(3.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryTimeWindow().getStart(), 0.01);
Assert.assertEquals(4.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryTimeWindow().getEnd(), 0.01);
assertEquals(3.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryTimeWindow().getStart(), 0.01);
assertEquals(4.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryTimeWindow().getEnd(), 0.01);
}
@Test
public void whenWritingShipments_readingThemAgainMustReturnTheWrittenDeliveryServiceTimeOfS1() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build();
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build();
builder.addVehicle(v1);
builder.addVehicle(v2);
VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls();
Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10)
.setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build())
@ -311,11 +195,7 @@ public class VrpXMLWriterTest {
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
assertEquals(2, readVrp.getJobs().size());
assertEquals(100.0, ((Shipment) readVrp.getJobs().get("1")).getPickupServiceTime(), 0.01);
@ -325,15 +205,7 @@ public class VrpXMLWriterTest {
@Test
public void whenWritingShipments_readingThemAgainMustReturnTheWrittenLocationIdOfS1() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build();
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build();
builder.addVehicle(v1);
builder.addVehicle(v2);
VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls();
Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10)
.setPickupLocation(TestUtils.loc(Coordinate.newInstance(1, 2))).setDeliveryLocation(TestUtils.loc("delLoc")).setPickupTimeWindow(TimeWindow.newInstance(1, 2))
@ -345,18 +217,14 @@ public class VrpXMLWriterTest {
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
assertEquals(2, readVrp.getJobs().size());
Assert.assertEquals("[x=1.0][y=2.0]", ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getId());
assertEquals("[x=1.0][y=2.0]", ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getId());
}
@Test
public void whenWritingVehicles_vehShouldHave2Skills() {
public void whenWritingVehicles_vehShouldHave3Skills() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleImpl v = VehicleImpl.Builder.newInstance("v1").addSkill("SKILL5").addSkill("skill1").addSkill("Skill2")
@ -364,70 +232,12 @@ public class VrpXMLWriterTest {
builder.addVehicle(v);
VehicleRoutingProblem vrp = builder.build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
Vehicle veh1 = getVehicle("v1", readVrp);
Assert.assertEquals(3, veh1.getSkills().values().size());
}
@Test
public void whenWritingVehicles_vehShouldContain_skill5() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleImpl v = VehicleImpl.Builder.newInstance("v1").addSkill("SKILL5").addSkill("skill1").addSkill("Skill2")
.setStartLocation(TestUtils.loc("loc")).setType(type1).build();
builder.addVehicle(v);
VehicleRoutingProblem vrp = builder.build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Vehicle veh1 = getVehicle("v1", readVrp);
assertEquals(3, veh1.getSkills().values().size());
assertTrue(veh1.getSkills().containsSkill("skill5"));
}
@Test
public void whenWritingVehicles_vehShouldContain_skill1() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleImpl v = VehicleImpl.Builder.newInstance("v1").addSkill("SKILL5").addSkill("skill1").addSkill("Skill2")
.setStartLocation(TestUtils.loc("loc")).setType(type1).build();
builder.addVehicle(v);
VehicleRoutingProblem vrp = builder.build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
Vehicle veh1 = getVehicle("v1", readVrp);
assertTrue(veh1.getSkills().containsSkill("skill1"));
}
@Test
public void whenWritingVehicles_vehShouldContain_skill2() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleImpl v = VehicleImpl.Builder.newInstance("v1").addSkill("SKILL5").addSkill("skill1").addSkill("Skill2")
.setStartLocation(TestUtils.loc("loc")).setType(type1).build();
builder.addVehicle(v);
VehicleRoutingProblem vrp = builder.build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
Vehicle veh1 = getVehicle("v1", readVrp);
assertTrue(veh1.getSkills().containsSkill("skill2"));
}
@ -439,14 +249,10 @@ public class VrpXMLWriterTest {
builder.addVehicle(v);
VehicleRoutingProblem vrp = builder.build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Vehicle veh = getVehicle("v1", readVrp);
Assert.assertEquals(0, veh.getSkills().values().size());
assertEquals(0, veh.getSkills().values().size());
}
private Vehicle getVehicle(String v1, VehicleRoutingProblem readVrp) {
@ -468,89 +274,17 @@ public class VrpXMLWriterTest {
.setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build();
VehicleRoutingProblem vrp = builder.addJob(s).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
Assert.assertEquals(3, readVrp.getJobs().get("1").getRequiredSkills().values().size());
}
@Test
public void whenWritingShipments_shipmentShouldContain_skill1() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
Shipment s = Shipment.Builder.newInstance("1").addRequiredSkill("skill1").addRequiredSkill("skill2").addRequiredSkill("skill3")
.addSizeDimension(0, 10)
.setPickupLocation(TestUtils.loc(Coordinate.newInstance(1, 2)))
.setDeliveryLocation(TestUtils.loc("delLoc", Coordinate.newInstance(5, 6)))
.setPickupTimeWindow(TimeWindow.newInstance(1, 2))
.setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build();
VehicleRoutingProblem vrp = builder.addJob(s).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
assertEquals(3, readVrp.getJobs().get("1").getRequiredSkills().values().size());
assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill1"));
}
@Test
public void whenWritingShipments_shipmentShouldContain_skill2() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
Shipment s = Shipment.Builder.newInstance("1").addRequiredSkill("skill1").addRequiredSkill("Skill2").addRequiredSkill("skill3")
.addSizeDimension(0, 10)
.setPickupLocation(TestUtils.loc(Coordinate.newInstance(1, 2)))
.setDeliveryLocation(TestUtils.loc("delLoc", Coordinate.newInstance(5, 6)))
.setPickupTimeWindow(TimeWindow.newInstance(1, 2))
.setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build();
VehicleRoutingProblem vrp = builder.addJob(s).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill2"));
}
@Test
public void whenWritingShipments_shipmentShouldContain_skill3() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
Shipment s = Shipment.Builder.newInstance("1").addRequiredSkill("skill1").addRequiredSkill("Skill2").addRequiredSkill("skill3")
.addSizeDimension(0, 10)
.setPickupLocation(TestUtils.loc(Coordinate.newInstance(1, 2)))
.setDeliveryLocation(TestUtils.loc("delLoc", Coordinate.newInstance(5, 6)))
.setPickupTimeWindow(TimeWindow.newInstance(1, 2))
.setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build();
VehicleRoutingProblem vrp = builder.addJob(s).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill3"));
}
@Test
public void whenWritingShipments_readingThemAgainMustReturnTheWrittenLocationCoordinateOfS1() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build();
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build();
builder.addVehicle(v1);
builder.addVehicle(v2);
VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls();
Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10).setPickupLocation(TestUtils.loc(Coordinate.newInstance(1, 2)))
.setDeliveryLocation(TestUtils.loc("delLoc", Coordinate.newInstance(5, 6)))
@ -564,18 +298,14 @@ public class VrpXMLWriterTest {
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
assertEquals(2, readVrp.getJobs().size());
Assert.assertEquals(1.0, ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getCoordinate().getX(), 0.01);
Assert.assertEquals(2.0, ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getCoordinate().getY(), 0.01);
assertEquals(1.0, ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getCoordinate().getX(), 0.01);
assertEquals(2.0, ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getCoordinate().getY(), 0.01);
Assert.assertEquals(5.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getCoordinate().getX(), 0.01);
Assert.assertEquals(6.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getCoordinate().getY(), 0.01);
assertEquals(5.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getCoordinate().getX(), 0.01);
assertEquals(6.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getCoordinate().getY(), 0.01);
}
@Test
@ -597,23 +327,34 @@ public class VrpXMLWriterTest {
.setDeliveryTimeWindow(TimeWindow.newInstance(7, 8)).build();
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
assertEquals(3, (readVrp.getJobs().get("1")).getSize().getNuOfDimensions());
assertEquals(10, (readVrp.getJobs().get("1")).getSize().get(0));
assertEquals(0, (readVrp.getJobs().get("1")).getSize().get(1));
assertEquals(100, (readVrp.getJobs().get("1")).getSize().get(2));
Assert.assertEquals(3, (readVrp.getJobs().get("1")).getSize().getNuOfDimensions());
Assert.assertEquals(10, (readVrp.getJobs().get("1")).getSize().get(0));
Assert.assertEquals(0, (readVrp.getJobs().get("1")).getSize().get(1));
Assert.assertEquals(100, (readVrp.getJobs().get("1")).getSize().get(2));
Assert.assertEquals(1, (readVrp.getJobs().get("2")).getSize().getNuOfDimensions());
Assert.assertEquals(20, (readVrp.getJobs().get("2")).getSize().get(0));
assertEquals(1, (readVrp.getJobs().get("2")).getSize().getNuOfDimensions());
assertEquals(20, (readVrp.getJobs().get("2")).getSize().get(0));
}
@Test
public void whenWritingVehicleV1_itsStartLocationMustBeWrittenCorrectly() {
VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls();
Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build();
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build();
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Vehicle v = getVehicle("v1", readVrp.getVehicles());
assertEquals("loc", v.getStartLocation().getId());
assertEquals("loc", v.getEndLocation().getId());
}
private VehicleRoutingProblem.Builder twoVehicleTypesAndImpls() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
@ -623,74 +364,27 @@ public class VrpXMLWriterTest {
builder.addVehicle(v1);
builder.addVehicle(v2);
Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build();
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build();
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
Vehicle v = getVehicle("v1", readVrp.getVehicles());
Assert.assertEquals("loc", v.getStartLocation().getId());
Assert.assertEquals("loc", v.getEndLocation().getId());
return builder;
}
@Test
public void whenWritingService_itShouldHaveTheCorrectNuSkills() {
public void whenWritingService_itShouldContain_bothSkills() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
Service s = Service.Builder.newInstance("1").addRequiredSkill("sKill1").addRequiredSkill("skill2").addSizeDimension(0, 1)
//skill names are case-insensitive
Service s = Service.Builder.newInstance("1").addRequiredSkill("skill1").addRequiredSkill("SKILL2").addSizeDimension(0, 1)
.setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build();
VehicleRoutingProblem vrp = builder.addJob(s).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
Assert.assertEquals(2, readVrp.getJobs().get("1").getRequiredSkills().values().size());
}
@Test
public void whenWritingService_itShouldContain_skill1() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
Service s = Service.Builder.newInstance("1").addRequiredSkill("sKill1").addRequiredSkill("skill2").addSizeDimension(0, 1)
.setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build();
VehicleRoutingProblem vrp = builder.addJob(s).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
assertEquals(2, readVrp.getJobs().get("1").getRequiredSkills().values().size());
assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill1"));
}
@Test
public void whenWritingService_itShouldContain_skill2() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
Service s = Service.Builder.newInstance("1").addRequiredSkill("sKill1").addRequiredSkill("skill2").addSizeDimension(0, 1)
.setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build();
VehicleRoutingProblem vrp = builder.addJob(s).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill2"));
}
@Test
public void whenWritingVehicleV1_itDoesNotReturnToDepotMustBeWrittenCorrectly() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
@ -708,11 +402,7 @@ public class VrpXMLWriterTest {
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build();
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Vehicle v = getVehicle("v1", readVrp.getVehicles());
assertFalse(v.isReturnToDepot());
@ -734,11 +424,7 @@ public class VrpXMLWriterTest {
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build();
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Vehicle v = getVehicle("v1", readVrp.getVehicles());
assertEquals("vehType", v.getType().getTypeId());
@ -760,15 +446,11 @@ public class VrpXMLWriterTest {
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build();
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Vehicle v = getVehicle("v2", readVrp.getVehicles());
assertEquals("vehType2", v.getType().getTypeId());
Assert.assertEquals(200, v.getType().getCapacityDimensions().get(0));
assertEquals(200, v.getType().getCapacityDimensions().get(0));
}
@ -776,35 +458,6 @@ public class VrpXMLWriterTest {
public void whenWritingVehicleV2_readingItsLocationsAgainReturnsCorrectLocations() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setReturnToDepot(false).setStartLocation(TestUtils.loc("loc")).setType(type1).build();
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2")
.setStartLocation(TestUtils.loc("startLoc", Coordinate.newInstance(1, 2)))
.setEndLocation(TestUtils.loc("endLoc", Coordinate.newInstance(4, 5))).setType(type2).build();
builder.addVehicle(v1);
builder.addVehicle(v2);
Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build();
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build();
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
Vehicle v = getVehicle("v2", readVrp.getVehicles());
Assert.assertEquals("startLoc", v.getStartLocation().getId());
Assert.assertEquals("endLoc", v.getEndLocation().getId());
}
@Test
public void whenWritingVehicleV2_readingItsLocationsCoordsAgainReturnsCorrectLocationsCoords() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build();
VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build();
VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setReturnToDepot(false)
@ -820,20 +473,18 @@ public class VrpXMLWriterTest {
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build();
VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Vehicle v = getVehicle("v2", readVrp.getVehicles());
Assert.assertEquals(1.0, v.getStartLocation().getCoordinate().getX(), 0.01);
Assert.assertEquals(2.0, v.getStartLocation().getCoordinate().getY(), 0.01);
Assert.assertEquals(4.0, v.getEndLocation().getCoordinate().getX(), 0.01);
Assert.assertEquals(5.0, v.getEndLocation().getCoordinate().getY(), 0.01);
assertEquals("startLoc", v.getStartLocation().getId());
assertEquals("endLoc", v.getEndLocation().getId());
assertEquals(1.0, v.getStartLocation().getCoordinate().getX(), 0.01);
assertEquals(2.0, v.getStartLocation().getCoordinate().getY(), 0.01);
assertEquals(4.0, v.getEndLocation().getCoordinate().getX(), 0.01);
assertEquals(5.0, v.getEndLocation().getCoordinate().getY(), 0.01);
}
@Test
public void whenWritingVehicleWithSeveralCapacityDimensions_itShouldBeWrittenAndRereadCorrectly() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
@ -850,17 +501,13 @@ public class VrpXMLWriterTest {
builder.addVehicle(v2);
VehicleRoutingProblem vrp = builder.build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Vehicle v = getVehicle("v", readVrp.getVehicles());
Assert.assertEquals(3, v.getType().getCapacityDimensions().getNuOfDimensions());
Assert.assertEquals(100, v.getType().getCapacityDimensions().get(0));
Assert.assertEquals(1000, v.getType().getCapacityDimensions().get(1));
Assert.assertEquals(10000, v.getType().getCapacityDimensions().get(2));
assertEquals(3, v.getType().getCapacityDimensions().getNuOfDimensions());
assertEquals(100, v.getType().getCapacityDimensions().get(0));
assertEquals(1000, v.getType().getCapacityDimensions().get(1));
assertEquals(10000, v.getType().getCapacityDimensions().get(2));
}
@Test
@ -879,16 +526,12 @@ public class VrpXMLWriterTest {
builder.addVehicle(v2);
VehicleRoutingProblem vrp = builder.build();
new VrpXMLWriter(vrp, null).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(infileName);
VehicleRoutingProblem readVrp = vrpToReadBuilder.build();
VehicleRoutingProblem readVrp = writeAndRereadXml(vrp);
Vehicle v = getVehicle("v", readVrp.getVehicles());
Assert.assertEquals(11, v.getType().getCapacityDimensions().getNuOfDimensions());
Assert.assertEquals(0, v.getType().getCapacityDimensions().get(9));
Assert.assertEquals(10000, v.getType().getCapacityDimensions().get(10));
assertEquals(11, v.getType().getCapacityDimensions().getNuOfDimensions());
assertEquals(0, v.getType().getCapacityDimensions().get(9));
assertEquals(10000, v.getType().getCapacityDimensions().get(10));
}
private Vehicle getVehicle(String string, Collection<Vehicle> vehicles) {
@ -916,14 +559,10 @@ public class VrpXMLWriterTest {
List<VehicleRoutingProblemSolution> solutions = new ArrayList<VehicleRoutingProblemSolution>();
solutions.add(solution);
new VrpXMLWriter(vrp, solutions).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
List<VehicleRoutingProblemSolution> solutionsToRead = new ArrayList<VehicleRoutingProblemSolution>();
new VrpXMLReader(vrpToReadBuilder, solutionsToRead).read(infileName);
List<VehicleRoutingProblemSolution> solutionsToRead = writeAndRereadXmlWithSolutions(vrp, solutions);
assertEquals(1, solutionsToRead.size());
Assert.assertEquals(10., Solutions.bestOf(solutionsToRead).getCost(), 0.01);
assertEquals(10., Solutions.bestOf(solutionsToRead).getCost(), 0.01);
assertTrue(Solutions.bestOf(solutionsToRead).getUnassignedJobs().isEmpty());
}
@ -948,16 +587,46 @@ public class VrpXMLWriterTest {
List<VehicleRoutingProblemSolution> solutions = new ArrayList<VehicleRoutingProblemSolution>();
solutions.add(solution);
new VrpXMLWriter(vrp, solutions).write(infileName);
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
List<VehicleRoutingProblemSolution> solutionsToRead = new ArrayList<VehicleRoutingProblemSolution>();
new VrpXMLReader(vrpToReadBuilder, solutionsToRead).read(infileName);
List<VehicleRoutingProblemSolution> solutionsToRead = writeAndRereadXmlWithSolutions(vrp, solutions);
assertEquals(1, solutionsToRead.size());
Assert.assertEquals(10., Solutions.bestOf(solutionsToRead).getCost(), 0.01);
Assert.assertEquals(1, Solutions.bestOf(solutionsToRead).getUnassignedJobs().size());
Assert.assertEquals("2", Solutions.bestOf(solutionsToRead).getUnassignedJobs().iterator().next().getId());
assertEquals(10., Solutions.bestOf(solutionsToRead).getCost(), 0.01);
assertEquals(1, Solutions.bestOf(solutionsToRead).getUnassignedJobs().size());
assertEquals("2", Solutions.bestOf(solutionsToRead).getUnassignedJobs().iterator().next().getId());
}
@Test
public void outputStreamAndFileContentsAreEqual() throws IOException {
VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls();
VehicleRoutingProblem vrp = builder.build();
VrpXMLWriter vrpXMLWriter = new VrpXMLWriter(vrp, null);
ByteArrayOutputStream os = (ByteArrayOutputStream) vrpXMLWriter.write();
String outputStringFromFile = new String(os.toByteArray());
String outputStringFromStream = new VrpXMLWriter(vrp, null).write().toString();
assertEquals(outputStringFromFile, outputStringFromStream);
}
private VehicleRoutingProblem writeAndRereadXml(VehicleRoutingProblem vrp) {
VrpXMLWriter vrpXMLWriter = new VrpXMLWriter(vrp, null);
ByteArrayOutputStream os = (ByteArrayOutputStream) vrpXMLWriter.write();
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
new VrpXMLReader(vrpToReadBuilder, null).read(is);
return vrpToReadBuilder.build();
}
private List<VehicleRoutingProblemSolution> writeAndRereadXmlWithSolutions(VehicleRoutingProblem vrp, List<VehicleRoutingProblemSolution> solutions) {
VrpXMLWriter vrpXMLWriter = new VrpXMLWriter(vrp, solutions);
ByteArrayOutputStream os = (ByteArrayOutputStream) vrpXMLWriter.write();
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance();
List<VehicleRoutingProblemSolution> solutionsToRead = new ArrayList<VehicleRoutingProblemSolution>();
new VrpXMLReader(vrpToReadBuilder, solutionsToRead).read(is);
return solutionsToRead;
}
}

20
pom.xml
View file

@ -22,7 +22,7 @@
<groupId>com.graphhopper</groupId>
<artifactId>jsprit</artifactId>
<version>1.6.3-SNAPSHOT</version>
<version>1.7.3-SNAPSHOT</version>
<packaging>pom</packaging>
@ -56,6 +56,7 @@
<tag>HEAD</tag>
</scm>
<issueManagement>
<system>github</system>
<url>https://github.com/graphhopper/jsprit/issues</url>
@ -81,6 +82,15 @@
</properties>
<build>
<extensions>
<extension>
<groupId>io.packagecloud.maven.wagon</groupId>
<artifactId>maven-packagecloud-wagon</artifactId>
<version>0.0.4</version>
</extension>
</extensions>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<directory>target</directory>
@ -180,9 +190,13 @@
</dependencies>
<distributionManagement>
<repository>
<id>packagecloud-graphhopper</id>
<url>packagecloud+https://packagecloud.io/graphhopper/jsprit</url>
</repository>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<id>packagecloud-graphhopper</id>
<url>packagecloud+https://packagecloud.io/graphhopper/jsprit</url>
</snapshotRepository>
</distributionManagement>