mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
ini
This commit is contained in:
commit
3581d6e097
435 changed files with 46952 additions and 0 deletions
28
jsprit-analysis/.classpath
Normal file
28
jsprit-analysis/.classpath
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry including="**/*.java" kind="src" path="src/main/resources"/>
|
||||||
|
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry including="**/*.java" kind="src" path="src/test/resources"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="output" path="target/classes"/>
|
||||||
|
</classpath>
|
||||||
23
jsprit-analysis/.project
Normal file
23
jsprit-analysis/.project
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>jsprit-analysis</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//src/main/java=UTF-8
|
||||||
|
encoding//src/main/resources=UTF-8
|
||||||
|
encoding//src/test/java=UTF-8
|
||||||
|
encoding//src/test/resources=UTF-8
|
||||||
|
encoding/<project>=UTF-8
|
||||||
|
encoding/src=UTF-8
|
||||||
12
jsprit-analysis/.settings/org.eclipse.jdt.core.prefs
Normal file
12
jsprit-analysis/.settings/org.eclipse.jdt.core.prefs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||||
|
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||||
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.6
|
||||||
4
jsprit-analysis/.settings/org.eclipse.m2e.core.prefs
Normal file
4
jsprit-analysis/.settings/org.eclipse.m2e.core.prefs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
activeProfiles=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
version=1
|
||||||
339
jsprit-analysis/license.txt
Normal file
339
jsprit-analysis/license.txt
Normal file
|
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
50
jsprit-analysis/pom.xml
Normal file
50
jsprit-analysis/pom.xml
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2013 Stefan Schroeder
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Stefan Schroeder - initial API and implementation
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>jsprit</groupId>
|
||||||
|
<artifactId>jsprit-project</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
<relativePath>../jsprit-project/pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>jsprit-analysis</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jfree</groupId>
|
||||||
|
<artifactId>jfreechart</artifactId>
|
||||||
|
<version>1.0.14</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>jsprit-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package analysis;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.jfree.chart.ChartFactory;
|
||||||
|
import org.jfree.chart.ChartUtilities;
|
||||||
|
import org.jfree.chart.JFreeChart;
|
||||||
|
import org.jfree.chart.axis.NumberAxis;
|
||||||
|
import org.jfree.chart.axis.NumberTickUnit;
|
||||||
|
import org.jfree.chart.plot.PlotOrientation;
|
||||||
|
import org.jfree.chart.plot.XYPlot;
|
||||||
|
import org.jfree.data.Range;
|
||||||
|
import org.jfree.data.xy.XYSeries;
|
||||||
|
import org.jfree.data.xy.XYSeriesCollection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.AlgorithmEndsListener;
|
||||||
|
import basics.algo.IterationEndsListener;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VehicleRoutingAlgorithm-Listener to record the solution-search-progress.
|
||||||
|
*
|
||||||
|
* <p>Register this listener in VehicleRoutingAlgorithm.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AlgorithmSearchProgressChartListener implements IterationEndsListener, AlgorithmEndsListener {
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(AlgorithmSearchProgressChartListener.class);
|
||||||
|
|
||||||
|
private double[] bestResults;
|
||||||
|
|
||||||
|
private double[] worstResults;
|
||||||
|
|
||||||
|
private double[] avgResults;
|
||||||
|
|
||||||
|
private List<Double> bestResultList = new ArrayList<Double>();
|
||||||
|
|
||||||
|
private List<Double> worstResultList = new ArrayList<Double>();
|
||||||
|
|
||||||
|
private List<Double> avgResultList = new ArrayList<Double>();
|
||||||
|
|
||||||
|
private String filename;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs chart listener with target png-file (filename plus path).
|
||||||
|
*
|
||||||
|
* @param pngFileName
|
||||||
|
*/
|
||||||
|
public AlgorithmSearchProgressChartListener(String pngFileName) {
|
||||||
|
super();
|
||||||
|
this.filename = pngFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
log.info("create chart " + filename);
|
||||||
|
if(bestResultList.isEmpty()){
|
||||||
|
log.warn("cannot create chart since no results available.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bestResults = new double[bestResultList.size()];
|
||||||
|
worstResults = new double[worstResultList.size()];
|
||||||
|
avgResults = new double[avgResultList.size()];
|
||||||
|
|
||||||
|
double maxValue = 0.0;
|
||||||
|
double minValue = Double.MAX_VALUE;
|
||||||
|
|
||||||
|
double[] iteration = new double[bestResultList.size()];
|
||||||
|
for (int i = 0; i < bestResultList.size(); i++) {
|
||||||
|
if(bestResultList.get(i) < minValue) minValue = bestResultList.get(i);
|
||||||
|
if(worstResultList.get(i) < minValue) minValue = worstResultList.get(i);
|
||||||
|
if(avgResultList.get(i) < minValue) minValue = avgResultList.get(i);
|
||||||
|
|
||||||
|
if(bestResultList.get(i) > maxValue) maxValue = bestResultList.get(i);
|
||||||
|
if(worstResultList.get(i) > maxValue) maxValue = worstResultList.get(i);
|
||||||
|
if(avgResultList.get(i) > maxValue) maxValue = avgResultList.get(i);
|
||||||
|
|
||||||
|
bestResults[i] = bestResultList.get(i);
|
||||||
|
worstResults[i] = worstResultList.get(i);
|
||||||
|
avgResults[i] = avgResultList.get(i);
|
||||||
|
iteration[i] = i;
|
||||||
|
}
|
||||||
|
XYSeriesCollection coll = new XYSeriesCollection();
|
||||||
|
JFreeChart chart = ChartFactory.createXYLineChart("search-progress","iterations", "results",coll, PlotOrientation.VERTICAL,true,true,false);
|
||||||
|
addSeries("bestResults", iteration, bestResults, coll);
|
||||||
|
addSeries("worstResults", iteration, worstResults, coll);
|
||||||
|
addSeries("avgResults", iteration, avgResults, coll);
|
||||||
|
|
||||||
|
XYPlot plot = chart.getXYPlot();
|
||||||
|
|
||||||
|
NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
|
||||||
|
Range rangeY = new Range(minValue-0.05*minValue,maxValue + 0.05*maxValue);
|
||||||
|
yAxis.setRange(rangeY);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ChartUtilities.saveChartAsJPEG(new File(filename), chart, 1000, 600);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSeries(String string, double[] iteration, double[] results, XYSeriesCollection coll) {
|
||||||
|
XYSeries series = new XYSeries(string, true, true);
|
||||||
|
for(int i=0;i<iteration.length;i++){
|
||||||
|
series.add(iteration[i], results[i]);
|
||||||
|
}
|
||||||
|
coll.addSeries(series);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informIterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
double worst = 0.0;
|
||||||
|
double best = Double.MAX_VALUE;
|
||||||
|
double sum = 0.0;
|
||||||
|
for(VehicleRoutingProblemSolution sol : solutions){
|
||||||
|
if(sol.getCost() > worst) worst = sol.getCost();
|
||||||
|
if(sol.getCost() < best) best = sol.getCost();
|
||||||
|
sum += sol.getCost();
|
||||||
|
}
|
||||||
|
bestResultList.add(best);
|
||||||
|
worstResultList.add(worst);
|
||||||
|
avgResultList.add(sum/(double)solutions.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
204
jsprit-analysis/src/main/java/analysis/SolutionPlotter.java
Normal file
204
jsprit-analysis/src/main/java/analysis/SolutionPlotter.java
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package analysis;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.jfree.chart.ChartFactory;
|
||||||
|
import org.jfree.chart.ChartUtilities;
|
||||||
|
import org.jfree.chart.JFreeChart;
|
||||||
|
import org.jfree.chart.axis.NumberAxis;
|
||||||
|
import org.jfree.chart.axis.NumberTickUnit;
|
||||||
|
import org.jfree.chart.plot.PlotOrientation;
|
||||||
|
import org.jfree.chart.plot.XYPlot;
|
||||||
|
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||||
|
import org.jfree.data.Range;
|
||||||
|
import org.jfree.data.xy.XYSeries;
|
||||||
|
import org.jfree.data.xy.XYSeriesCollection;
|
||||||
|
|
||||||
|
import util.Coordinate;
|
||||||
|
import util.Locations;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A plotter to plot vehicle-routing-solution and routes respectively.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SolutionPlotter {
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(SolutionPlotter.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plots the solution to pngFile, with title.
|
||||||
|
*
|
||||||
|
* <p>This can only plot if vehicles and jobs have locationIds and coordinates (@see Coordinate). Otherwise a warning message is logged
|
||||||
|
* and method returns but does not plot.
|
||||||
|
*
|
||||||
|
* @param vrp
|
||||||
|
* @param solution
|
||||||
|
* @param pngFile target path with filename.
|
||||||
|
* @see VehicleRoutingProblem, VehicleRoutingProblemSolution
|
||||||
|
*/
|
||||||
|
public static void plotSolutionAsPNG(VehicleRoutingProblem vrp, VehicleRoutingProblemSolution solution, String pngFile, String plotTitle){
|
||||||
|
final Map<String,Coordinate> locs = new HashMap<String, Coordinate>();
|
||||||
|
boolean locationsRetrieved = retrieveLocations(locs,vrp);
|
||||||
|
if(!locationsRetrieved) return;
|
||||||
|
Locations locations = new Locations(){
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Coordinate getCoord(String id) {
|
||||||
|
return locs.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
plotRoutesAsPNG(solution.getRoutes(), locations, pngFile, plotTitle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plots the a collection of routes to pngFile.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param routes
|
||||||
|
* @param locations indicating the locations for the tour-activities.
|
||||||
|
* @param pngFile target path with filename.
|
||||||
|
* @param plotTitle
|
||||||
|
* @see VehicleRoute
|
||||||
|
*/
|
||||||
|
public static void plotRoutesAsPNG(Collection<VehicleRoute> routes, Locations locations, String pngFile, String plotTitle) {
|
||||||
|
log.info("plot routes to " + pngFile);
|
||||||
|
XYSeriesCollection coll = new XYSeriesCollection();
|
||||||
|
int counter = 1;
|
||||||
|
double maxX = 0;
|
||||||
|
double minX = Double.MAX_VALUE;
|
||||||
|
double maxY = 0;
|
||||||
|
double minY = Double.MAX_VALUE;
|
||||||
|
for(VehicleRoute route : routes){
|
||||||
|
if(route.isEmpty()) continue;
|
||||||
|
XYSeries series = new XYSeries(counter, false, true);
|
||||||
|
|
||||||
|
Coordinate startCoord = locations.getCoord(route.getStart().getLocationId());
|
||||||
|
series.add(startCoord.getX(), startCoord.getY());
|
||||||
|
if(startCoord.getX() > maxX) maxX = startCoord.getX();
|
||||||
|
if(startCoord.getY() > maxY) maxY = startCoord.getY();
|
||||||
|
if(startCoord.getX() < minX) minX = startCoord.getX();
|
||||||
|
if(startCoord.getY() < minY) minY = startCoord.getY();
|
||||||
|
|
||||||
|
for(TourActivity act : route.getTourActivities().getActivities()){
|
||||||
|
Coordinate coord = locations.getCoord(act.getLocationId());
|
||||||
|
series.add(coord.getX(), coord.getY());
|
||||||
|
if(coord.getX() > maxX) maxX = coord.getX();
|
||||||
|
if(coord.getY() > maxY) maxY = coord.getY();
|
||||||
|
if(coord.getX() < minX) minX = coord.getX();
|
||||||
|
if(coord.getY() < minY) minY = coord.getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
Coordinate endCoord = locations.getCoord(route.getEnd().getLocationId());
|
||||||
|
series.add(endCoord.getX(), endCoord.getY());
|
||||||
|
if(endCoord.getX() > maxX) maxX = endCoord.getX();
|
||||||
|
if(endCoord.getY() > maxY) maxY = endCoord.getY();
|
||||||
|
if(endCoord.getX() < minX) minX = endCoord.getX();
|
||||||
|
if(endCoord.getY() < minY) minY = endCoord.getY();
|
||||||
|
|
||||||
|
coll.addSeries(series);
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
JFreeChart chart = ChartFactory.createXYLineChart(plotTitle,"x-coordinate", "y-coordinate",coll, PlotOrientation.VERTICAL,true,true,false);
|
||||||
|
|
||||||
|
XYPlot plot = chart.getXYPlot();
|
||||||
|
|
||||||
|
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer();
|
||||||
|
renderer.setBaseShapesVisible(true);
|
||||||
|
|
||||||
|
NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();
|
||||||
|
xAxis.setTickUnit(new NumberTickUnit(10));
|
||||||
|
// Range rangeX = new Range(minX - 0.05*minX, maxX+0.05*maxX);
|
||||||
|
Range rangeX = new Range(minX, maxX);
|
||||||
|
xAxis.setRange(rangeX);
|
||||||
|
|
||||||
|
NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
|
||||||
|
// yAxis.setTickUnit(new NumberTickUnit(10));
|
||||||
|
// Range rangeY = new Range(minY-0.05*minY,maxY + 0.05*maxY);
|
||||||
|
Range rangeY = new Range(minY,maxY);
|
||||||
|
yAxis.setRange(rangeY);
|
||||||
|
try {
|
||||||
|
ChartUtilities.saveChartAsPNG(new File(pngFile), chart, 1000, 600);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("cannot plot");
|
||||||
|
log.error(e);
|
||||||
|
e.printStackTrace();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean retrieveLocations(Map<String, Coordinate> locs, VehicleRoutingProblem vrp) {
|
||||||
|
for(Vehicle v : vrp.getVehicles()){
|
||||||
|
String locationId = v.getLocationId();
|
||||||
|
if(locationId == null){
|
||||||
|
log.warn("cannot plot solution, since vehicle " + v + " has no locationId.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Coordinate coord = v.getCoord();
|
||||||
|
if(coord == null){
|
||||||
|
log.warn("cannot plot solution, since vehicle " + v + " has no location-coordinate.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
locs.put(locationId, coord);
|
||||||
|
}
|
||||||
|
for(Job j : vrp.getJobs().values()){
|
||||||
|
if(j instanceof Service){
|
||||||
|
String locationId = ((Service) j).getLocationId();
|
||||||
|
if(locationId == null){
|
||||||
|
log.warn("cannot plot solution, since job " + j + " has no locationId.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Coordinate coord = ((Service) j).getCoord();
|
||||||
|
if(coord == null){
|
||||||
|
log.warn("cannot plot solution, since job " + j + " has no location-coordinate.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
locs.put(locationId, coord);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw new IllegalStateException("job is not a service. this is not supported yet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
91
jsprit-analysis/src/main/java/analysis/SolutionPrinter.java
Normal file
91
jsprit-analysis/src/main/java/analysis/SolutionPrinter.java
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package analysis;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.route.DefaultVehicleRouteCostCalculator;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Printer to print the details of a vehicle-routing-problem solution.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SolutionPrinter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum to indicate verbose-level.
|
||||||
|
*
|
||||||
|
* <p> Print.CONCISE and Print.VERBOSE are available.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum Print {
|
||||||
|
|
||||||
|
CONCISE,VERBOSE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints costs and #vehicles to stdout (System.out.println).
|
||||||
|
*
|
||||||
|
* @param solution
|
||||||
|
*/
|
||||||
|
public static void print(VehicleRoutingProblemSolution solution){
|
||||||
|
System.out.println("[costs="+solution.getCost() + "]");
|
||||||
|
System.out.println("[#vehicles="+solution.getRoutes().size() + "]");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the details of the solution according to a print-level, i.e. Print.CONCISE or PRINT.VERBOSE.
|
||||||
|
*
|
||||||
|
* <p>CONCISE prints total-costs and #vehicles.
|
||||||
|
* <p>VERBOSE prints the route-details additionally. If the DefaultVehicleRouteCostCalculator (which is the standard-calculator)
|
||||||
|
* is used in VehicleRoute, then route-costs are differentiated further between transport, activity, vehicle, driver and other-costs.
|
||||||
|
*
|
||||||
|
* @param solution
|
||||||
|
* @param level
|
||||||
|
*/
|
||||||
|
public static void print(VehicleRoutingProblemSolution solution, Print level){
|
||||||
|
if(level.equals(Print.CONCISE)){
|
||||||
|
print(solution);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print(solution);
|
||||||
|
System.out.println("routes");
|
||||||
|
int routeCount = 1;
|
||||||
|
for(VehicleRoute route : solution.getRoutes()){
|
||||||
|
System.out.println("[route="+routeCount+"][departureTime="+route.getStart().getEndTime()+"[total=" + route.getCost() + "]");
|
||||||
|
if(route.getVehicleRouteCostCalculator() instanceof DefaultVehicleRouteCostCalculator){
|
||||||
|
DefaultVehicleRouteCostCalculator defaultCalc = (DefaultVehicleRouteCostCalculator) route.getVehicleRouteCostCalculator();
|
||||||
|
System.out.println("[transport=" + defaultCalc.getTpCosts() + "][activity=" + defaultCalc.getActCosts() +
|
||||||
|
"][vehicle=" + defaultCalc.getVehicleCosts() + "][driver=" + defaultCalc.getDriverCosts() + "][other=" + defaultCalc.getOther() + "]");
|
||||||
|
}
|
||||||
|
routeCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
80
jsprit-analysis/src/main/java/analysis/StopWatch.java
Normal file
80
jsprit-analysis/src/main/java/analysis/StopWatch.java
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package analysis;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingAlgorithm;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.AlgorithmEndsListener;
|
||||||
|
import basics.algo.AlgorithmStartsListener;
|
||||||
|
|
||||||
|
public class StopWatch implements AlgorithmStartsListener, AlgorithmEndsListener{
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(StopWatch.class);
|
||||||
|
|
||||||
|
private double ran;
|
||||||
|
|
||||||
|
private double startTime;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
reset();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getCompTimeInSeconds(){
|
||||||
|
return (ran)/1000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
stop();
|
||||||
|
log.info("computation time [in sec]: " + getCompTimeInSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop(){
|
||||||
|
ran += System.currentTimeMillis() - startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(){
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset(){
|
||||||
|
startTime = 0;
|
||||||
|
ran = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "stopWatch: " + getCompTimeInSeconds() + " sec";
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getCurrTimeInSeconds() {
|
||||||
|
return (System.currentTimeMillis()-startTime)/1000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
BIN
jsprit-core/.DS_Store
vendored
Normal file
BIN
jsprit-core/.DS_Store
vendored
Normal file
Binary file not shown.
30
jsprit-core/.classpath
Normal file
30
jsprit-core/.classpath
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry including="**/*.java" kind="src" path="src/test/resources"/>
|
||||||
|
<classpathentry including="**/*.java" kind="src" path="src/main/resources"/>
|
||||||
|
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="output" path="target/classes"/>
|
||||||
|
</classpath>
|
||||||
29
jsprit-core/.project
Normal file
29
jsprit-core/.project
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>jsprit-core</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.maven.ide.eclipse.maven2Builder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
<nature>org.maven.ide.eclipse.maven2Nature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
7
jsprit-core/.settings/org.eclipse.core.resources.prefs
Normal file
7
jsprit-core/.settings/org.eclipse.core.resources.prefs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//src/main/java=UTF-8
|
||||||
|
encoding//src/main/resources=UTF-8
|
||||||
|
encoding//src/test/java=UTF-8
|
||||||
|
encoding//src/test/resources=UTF-8
|
||||||
|
encoding/<project>=UTF-8
|
||||||
|
encoding/src=UTF-8
|
||||||
8
jsprit-core/.settings/org.eclipse.jdt.core.prefs
Normal file
8
jsprit-core/.settings/org.eclipse.jdt.core.prefs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||||
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.6
|
||||||
4
jsprit-core/.settings/org.eclipse.m2e.core.prefs
Normal file
4
jsprit-core/.settings/org.eclipse.m2e.core.prefs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
activeProfiles=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
version=1
|
||||||
9
jsprit-core/.settings/org.maven.ide.eclipse.prefs
Normal file
9
jsprit-core/.settings/org.maven.ide.eclipse.prefs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#Fri Mar 15 09:09:12 CET 2013
|
||||||
|
activeProfiles=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
fullBuildGoals=process-test-resources
|
||||||
|
includeModules=false
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
resourceFilterGoals=process-resources resources\:testResources
|
||||||
|
skipCompilerPlugin=true
|
||||||
|
version=1
|
||||||
339
jsprit-core/license.txt
Normal file
339
jsprit-core/license.txt
Normal file
|
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
60
jsprit-core/pom.xml
Normal file
60
jsprit-core/pom.xml
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2013 Stefan Schroeder
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Stefan Schroeder - initial API and implementation
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<groupId>jsprit</groupId>
|
||||||
|
<artifactId>jsprit-project</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
<relativePath>../jsprit-project/pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>jsprit-core</artifactId>
|
||||||
|
<name>jsprit-core</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-math</artifactId>
|
||||||
|
<version>2.2</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-configuration</groupId>
|
||||||
|
<artifactId>commons-configuration</artifactId>
|
||||||
|
<version>1.9</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>xerces</groupId>
|
||||||
|
<artifactId>xerces</artifactId>
|
||||||
|
<version>2.4.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.algo.InsertionEndsListener;
|
||||||
|
import basics.algo.InsertionListener;
|
||||||
|
import basics.algo.InsertionStartsListener;
|
||||||
|
import basics.algo.JobInsertedListener;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
abstract class AbstractInsertionStrategy implements InsertionStrategy{
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(AbstractInsertionStrategy.class);
|
||||||
|
|
||||||
|
private Collection<InsertionListener> listener = new ArrayList<InsertionListener>();
|
||||||
|
|
||||||
|
public abstract RouteAlgorithm getRouteAlgorithm();
|
||||||
|
|
||||||
|
public void informJobInserted(int nOfJobs2Recreate, Job insertedJob, VehicleRoute insertedIn){
|
||||||
|
for(InsertionListener l : listener){
|
||||||
|
if(l instanceof JobInsertedListener){
|
||||||
|
((JobInsertedListener)l).informJobInserted(nOfJobs2Recreate, insertedJob, insertedIn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route){
|
||||||
|
for(InsertionListener l : listener){
|
||||||
|
if(l instanceof BeforeJobInsertionListener){
|
||||||
|
((BeforeJobInsertionListener)l).informBeforeJobInsertion(job, data, route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2Recreate){
|
||||||
|
for(InsertionListener l : listener){
|
||||||
|
if(l instanceof InsertionStartsListener){
|
||||||
|
((InsertionStartsListener)l).informInsertionStarts(vehicleRoutes,nOfJobs2Recreate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void informInsertionEndsListeners(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
|
for(InsertionListener l : listener){
|
||||||
|
if(l instanceof InsertionEndsListener){
|
||||||
|
((InsertionEndsListener)l).informInsertionEnds(vehicleRoutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<InsertionListener> getListener() {
|
||||||
|
return Collections.unmodifiableCollection(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(InsertionListener l){
|
||||||
|
log.info("add insertion-listener " + l);
|
||||||
|
listener.add(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAllListener(List<InsertionListener> list) {
|
||||||
|
for(InsertionListener l : list) addListener(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.Driver;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
|
||||||
|
|
||||||
|
final class AuxilliaryCostCalculator {
|
||||||
|
|
||||||
|
private final VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
|
private final VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
public AuxilliaryCostCalculator(final VehicleRoutingTransportCosts routingCosts, final VehicleRoutingActivityCosts costFunction) {
|
||||||
|
super();
|
||||||
|
this.routingCosts = routingCosts;
|
||||||
|
this.activityCosts = costFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* @param depTime
|
||||||
|
* @param driver
|
||||||
|
* @param vehicle
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public double costOfPath(final List<TourActivity> path, final double depTime, final Driver driver, final Vehicle vehicle){
|
||||||
|
if(path.isEmpty()){
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
double cost = 0.0;
|
||||||
|
Iterator<TourActivity> actIter = path.iterator();
|
||||||
|
TourActivity prevAct = actIter.next();
|
||||||
|
double startCost = 0.0;
|
||||||
|
cost += startCost;
|
||||||
|
double departureTimePrevAct = depTime;
|
||||||
|
while(actIter.hasNext()){
|
||||||
|
TourActivity act = actIter.next();
|
||||||
|
double transportCost = routingCosts.getTransportCost(prevAct.getLocationId(), act.getLocationId(), departureTimePrevAct, driver, vehicle);
|
||||||
|
double transportTime = routingCosts.getTransportTime(prevAct.getLocationId(), act.getLocationId(), departureTimePrevAct, driver, vehicle);
|
||||||
|
cost += transportCost;
|
||||||
|
double actStartTime = departureTimePrevAct + transportTime;
|
||||||
|
double earliestOperationStartTime = Math.max(actStartTime, act.getTheoreticalEarliestOperationStartTime());
|
||||||
|
double actEndTime = earliestOperationStartTime + act.getOperationTime();
|
||||||
|
departureTimePrevAct = actEndTime;
|
||||||
|
cost += activityCosts.getActivityCost(act, actStartTime, driver, vehicle);
|
||||||
|
prevAct = act;
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double costOfPath(String startLocationId, final double startTime, final List<TourActivity> path, String endLocationId, final Driver driver, final Vehicle vehicle){
|
||||||
|
if(path.isEmpty()){
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
double cost = 0.0;
|
||||||
|
// Iterator<TourActivity> actIter = path.iterator();
|
||||||
|
String prevActLocation = startLocationId;
|
||||||
|
// TourActivity prevAct = actIter.next();
|
||||||
|
double startCost = 0.0;
|
||||||
|
cost += startCost;
|
||||||
|
double departureTimePrevAct = startTime;
|
||||||
|
for(TourActivity act : path){
|
||||||
|
// TourActivity act = actIter.next();
|
||||||
|
double transportCost = routingCosts.getTransportCost(prevActLocation, act.getLocationId(), departureTimePrevAct, driver, vehicle);
|
||||||
|
double transportTime = routingCosts.getTransportTime(prevActLocation, act.getLocationId(), departureTimePrevAct, driver, vehicle);
|
||||||
|
cost += transportCost;
|
||||||
|
double actStartTime = departureTimePrevAct + transportTime;
|
||||||
|
double earliestOperationStartTime = Math.max(actStartTime, act.getTheoreticalEarliestOperationStartTime());
|
||||||
|
double actEndTime = earliestOperationStartTime + act.getOperationTime();
|
||||||
|
departureTimePrevAct = actEndTime;
|
||||||
|
cost += activityCosts.getActivityCost(act, actStartTime, driver, vehicle);
|
||||||
|
prevActLocation = act.getLocationId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*!!! ENDLOCATION
|
||||||
|
=> Start u. End können primitiv sein.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.algo.InsertionListener;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
interface BeforeJobInsertionListener extends InsertionListener{
|
||||||
|
|
||||||
|
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route);
|
||||||
|
|
||||||
|
}
|
||||||
160
jsprit-core/src/main/java/algorithms/BestInsertion.java
Normal file
160
jsprit-core/src/main/java/algorithms/BestInsertion.java
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.RandomNumberGeneration;
|
||||||
|
import algorithms.InsertionData.NoInsertionFound;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplest recreation strategy. All removed customers are inserted where
|
||||||
|
* insertion costs are minimal. I.e. each tour-agent is asked for minimal
|
||||||
|
* marginal insertion costs. The tour-agent offering the lowest marginal
|
||||||
|
* insertion costs gets the customer/shipment.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class BestInsertion extends AbstractInsertionStrategy{
|
||||||
|
|
||||||
|
public static BestInsertion newInstance(RouteAlgorithm routeAlgorithm){
|
||||||
|
return new BestInsertion(routeAlgorithm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(BestInsertion.class);
|
||||||
|
|
||||||
|
private Random random = RandomNumberGeneration.getRandom();
|
||||||
|
|
||||||
|
private RouteAlgorithm routeAlgorithm;
|
||||||
|
|
||||||
|
private Map<String,VehicleRoute> experimentalPreferredRoute = new HashMap<String, VehicleRoute>();
|
||||||
|
|
||||||
|
public void setExperimentalPreferredRoute(Map<String, VehicleRoute> experimentalPreferredRoute) {
|
||||||
|
this.experimentalPreferredRoute = experimentalPreferredRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean allowUnassignedJobs = false;
|
||||||
|
|
||||||
|
private boolean fixRouteSet = false;
|
||||||
|
|
||||||
|
private boolean minVehiclesFirst = false;
|
||||||
|
|
||||||
|
public void setFixRouteSet(boolean fixRouteSet) {
|
||||||
|
this.fixRouteSet = fixRouteSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRandom(Random random) {
|
||||||
|
this.random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BestInsertion(RouteAlgorithm routeAlgorithm) {
|
||||||
|
super();
|
||||||
|
this.routeAlgorithm = routeAlgorithm;
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteAlgorithm getRouteAlgorithm(){
|
||||||
|
return routeAlgorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=bestInsertion]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs, double result2beat) {
|
||||||
|
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
|
||||||
|
Collections.shuffle(unassignedJobList, random);
|
||||||
|
informInsertionStarts(vehicleRoutes,unassignedJobs.size());
|
||||||
|
int inserted = 0;
|
||||||
|
List<String> reasons = new ArrayList<String>();
|
||||||
|
for(Job unassignedJob : unassignedJobList){
|
||||||
|
|
||||||
|
VehicleRoute insertIn = null;
|
||||||
|
Insertion bestInsertion = null;
|
||||||
|
double bestInsertionCost = Double.MAX_VALUE;
|
||||||
|
for(VehicleRoute vehicleRoute : vehicleRoutes){
|
||||||
|
InsertionData iData = routeAlgorithm.calculateBestInsertion(vehicleRoute, unassignedJob, bestInsertionCost);
|
||||||
|
if(iData instanceof NoInsertionFound) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(iData.getInsertionCost() < bestInsertionCost){
|
||||||
|
bestInsertion = new Insertion(vehicleRoute,iData);
|
||||||
|
bestInsertionCost = iData.getInsertionCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!minVehiclesFirst){
|
||||||
|
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
||||||
|
InsertionData newIData = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE);
|
||||||
|
if(newIData.getInsertionCost() < bestInsertionCost){
|
||||||
|
bestInsertion = new Insertion(newRoute,newIData);
|
||||||
|
bestInsertionCost = newIData.getInsertionCost();
|
||||||
|
vehicleRoutes.add(newRoute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(bestInsertion != null){
|
||||||
|
informBeforeJobInsertion(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||||
|
insertIn = bestInsertion.getRoute();
|
||||||
|
// logger.debug("insert job="+unassignedJob+" at index=" + bestInsertion.getInsertionData().getInsertionIndex() + " delta cost=" + bestInsertion.getInsertionData().getInsertionCost());
|
||||||
|
routeAlgorithm.insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(fixRouteSet){
|
||||||
|
if(allowUnassignedJobs) logger.warn("cannot insert job yet " + unassignedJob);
|
||||||
|
else throw new IllegalStateException("given the vehicles, could not insert job\n");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
||||||
|
InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE);
|
||||||
|
if(bestI instanceof InsertionData.NoInsertionFound){
|
||||||
|
if(allowUnassignedJobs){
|
||||||
|
logger.warn("cannot insert job yet " + unassignedJob);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(String s : reasons){
|
||||||
|
System.out.println("reason="+s);
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("given the vehicles, could not insert job\n" +
|
||||||
|
"\t" + unassignedJob + "\n\t");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
insertIn = newRoute;
|
||||||
|
informBeforeJobInsertion(unassignedJob,bestI,newRoute);
|
||||||
|
routeAlgorithm.insertJob(unassignedJob,bestI,newRoute);
|
||||||
|
vehicleRoutes.add(newRoute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inserted++;
|
||||||
|
informJobInserted((unassignedJobList.size()-inserted), unassignedJob, insertIn);
|
||||||
|
}
|
||||||
|
informInsertionEndsListeners(vehicleRoutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.CompletionService;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorCompletionService;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.RandomNumberGeneration;
|
||||||
|
import algorithms.InsertionData.NoInsertionFound;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplest recreation strategy. All removed customers are inserted where
|
||||||
|
* insertion costs are minimal. I.e. each tour-agent is asked for minimal
|
||||||
|
* marginal insertion costs. The tour-agent offering the lowest marginal
|
||||||
|
* insertion costs gets the customer/shipment.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class BestInsertionConcurrent extends AbstractInsertionStrategy{
|
||||||
|
|
||||||
|
|
||||||
|
static class Batch {
|
||||||
|
List<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(BestInsertionConcurrent.class);
|
||||||
|
|
||||||
|
private Random random = RandomNumberGeneration.getRandom();
|
||||||
|
|
||||||
|
private RouteAlgorithm routeAlgorithm;
|
||||||
|
|
||||||
|
// private ExecutorService executor;
|
||||||
|
|
||||||
|
private int nuOfBatches;
|
||||||
|
|
||||||
|
private ExecutorCompletionService<Insertion> completionService;
|
||||||
|
|
||||||
|
public void setRandom(Random random) {
|
||||||
|
this.random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BestInsertionConcurrent(RouteAlgorithm routeAlgorithm, ExecutorService executor, int nuOfThreads) {
|
||||||
|
super();
|
||||||
|
this.routeAlgorithm = routeAlgorithm;
|
||||||
|
// this.executor = executor;
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
this.nuOfBatches = nuOfThreads;
|
||||||
|
completionService = new ExecutorCompletionService<Insertion>(executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=concurrentBestInsertion]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs, double result2beat) {
|
||||||
|
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
|
||||||
|
Collections.shuffle(unassignedJobList, random);
|
||||||
|
informInsertionStarts(vehicleRoutes,unassignedJobs.size());
|
||||||
|
|
||||||
|
int inserted = 0;
|
||||||
|
for(final Job unassignedJob : unassignedJobList){
|
||||||
|
VehicleRoute insertIn = null;
|
||||||
|
Insertion bestInsertion = null;
|
||||||
|
double bestInsertionCost = Double.MAX_VALUE;
|
||||||
|
|
||||||
|
List<Batch> batches = distributeRoutes(vehicleRoutes,nuOfBatches);
|
||||||
|
|
||||||
|
for(final Batch batch : batches){
|
||||||
|
completionService.submit(new Callable<Insertion>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Insertion call() throws Exception {
|
||||||
|
return getBestInsertion(batch,unassignedJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
for(int i=0;i<batches.size();i++){
|
||||||
|
Future<Insertion> futureIData = completionService.take();
|
||||||
|
Insertion insertion = futureIData.get();
|
||||||
|
if(insertion == null) continue;
|
||||||
|
if(insertion.getInsertionData().getInsertionCost() < bestInsertionCost){
|
||||||
|
bestInsertion = insertion;
|
||||||
|
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(InterruptedException e){
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
catch (ExecutionException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
logger.error(e.getCause().toString());
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bestInsertion != null){
|
||||||
|
informBeforeJobInsertion(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||||
|
insertIn = bestInsertion.getRoute();
|
||||||
|
// logger.debug("insert job="+unassignedJob+" at index=" + bestInsertion.getInsertionData().getInsertionIndex() + " delta cost=" + bestInsertion.getInsertionData().getInsertionCost());
|
||||||
|
routeAlgorithm.insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
||||||
|
InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE);
|
||||||
|
if(bestI instanceof InsertionData.NoInsertionFound)
|
||||||
|
throw new IllegalStateException("given the vehicles, could not create a valid solution.\n\tthe reason might be" +
|
||||||
|
" inappropriate vehicle capacity.\n\tthe job that does not fit in any vehicle anymore is \n\t" + unassignedJob);
|
||||||
|
insertIn = newRoute;
|
||||||
|
informBeforeJobInsertion(unassignedJob,bestI,newRoute);
|
||||||
|
routeAlgorithm.insertJob(unassignedJob,bestI,newRoute);
|
||||||
|
vehicleRoutes.add(newRoute);
|
||||||
|
}
|
||||||
|
inserted++;
|
||||||
|
informJobInserted((unassignedJobList.size()-inserted), unassignedJob, insertIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
|
||||||
|
Insertion bestInsertion = null;
|
||||||
|
double bestInsertionCost = Double.MAX_VALUE;
|
||||||
|
for(VehicleRoute vehicleRoute : batch.routes){
|
||||||
|
InsertionData iData = routeAlgorithm.calculateBestInsertion(vehicleRoute, unassignedJob, bestInsertionCost);
|
||||||
|
if(iData instanceof NoInsertionFound) continue;
|
||||||
|
if(iData.getInsertionCost() < bestInsertionCost){
|
||||||
|
bestInsertion = new Insertion(vehicleRoute,iData);
|
||||||
|
bestInsertionCost = iData.getInsertionCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestInsertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Batch> distributeRoutes(Collection<VehicleRoute> vehicleRoutes, int nuOfBatches) {
|
||||||
|
List<Batch> batches = new ArrayList<Batch>();
|
||||||
|
for(int i=0;i<nuOfBatches;i++) batches.add(new Batch());
|
||||||
|
if(vehicleRoutes.size()<nuOfBatches){
|
||||||
|
int nOfNewRoutes = nuOfBatches-vehicleRoutes.size();
|
||||||
|
for(int i=0;i<nOfNewRoutes;i++){
|
||||||
|
vehicleRoutes.add(VehicleRoute.emptyRoute());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int count = 0;
|
||||||
|
for(VehicleRoute route : vehicleRoutes){
|
||||||
|
if(count == nuOfBatches) count=0;
|
||||||
|
batches.get(count).routes.add(route);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return batches;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RouteAlgorithm getRouteAlgorithm() {
|
||||||
|
return routeAlgorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import algorithms.RouteStates.ActivityState;
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.Driver;
|
||||||
|
import basics.route.End;
|
||||||
|
import basics.route.Start;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class CalculatesActivityInsertionWithHardTimeWindows {
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(CalculatesActivityInsertionWithHardTimeWindows.class);
|
||||||
|
|
||||||
|
private RouteStates routeStates;
|
||||||
|
|
||||||
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
|
private VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
public CalculatesActivityInsertionWithHardTimeWindows(RouteStates activityStates, VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts){
|
||||||
|
this.routeStates = activityStates;
|
||||||
|
this.routingCosts = routingCosts;
|
||||||
|
this.activityCosts = activityCosts;
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double calculate(VehicleRoute vehicleRoute, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle) {
|
||||||
|
boolean prevIsStart = false;
|
||||||
|
|
||||||
|
if(prevAct instanceof Start){
|
||||||
|
prevIsStart = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
|
||||||
|
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
|
||||||
|
|
||||||
|
double newAct_arrTime = prevAct.getEndTime() + tp_time_prevAct_newAct;
|
||||||
|
double newAct_operationStartTime = Math.max(newAct_arrTime, newAct.getTheoreticalEarliestOperationStartTime());
|
||||||
|
|
||||||
|
double newAct_endTime = newAct_operationStartTime + newAct.getOperationTime();
|
||||||
|
|
||||||
|
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, driver, vehicle);
|
||||||
|
|
||||||
|
double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle);
|
||||||
|
double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle);
|
||||||
|
|
||||||
|
double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct;
|
||||||
|
double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, driver, vehicle);
|
||||||
|
|
||||||
|
double activityInsertionCosts;
|
||||||
|
|
||||||
|
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct;
|
||||||
|
|
||||||
|
if(nextAct_arrTime > getLatestOperationStart(nextAct)){
|
||||||
|
activityInsertionCosts = Double.MAX_VALUE;
|
||||||
|
}
|
||||||
|
else if(vehicleRoute.isEmpty()){
|
||||||
|
activityInsertionCosts = totalCosts;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
double oldCostOfPrevAct;
|
||||||
|
if(prevIsStart) oldCostOfPrevAct = 0.0;
|
||||||
|
else oldCostOfPrevAct = state(prevAct).getCurrentCost();
|
||||||
|
double oldCostOfNextAct;
|
||||||
|
if(nextAct instanceof End) oldCostOfNextAct = routeStates.getRouteState(vehicleRoute).getCosts();
|
||||||
|
else oldCostOfNextAct = state(nextAct).getCurrentCost();
|
||||||
|
activityInsertionCosts = (totalCosts) - (oldCostOfNextAct-oldCostOfPrevAct);
|
||||||
|
}
|
||||||
|
return activityInsertionCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActivityState state(TourActivity act) {
|
||||||
|
return routeStates.getState(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getLatestOperationStart(TourActivity act) {
|
||||||
|
if(state(act) != null){
|
||||||
|
return state(act).getLatestOperationStart();
|
||||||
|
}
|
||||||
|
return act.getTheoreticalLatestOperationStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=calculatesHardTimeWindowActivityInsertion]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,209 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.Neighborhood;
|
||||||
|
|
||||||
|
import algorithms.RouteStates.ActivityState;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.Driver;
|
||||||
|
import basics.route.End;
|
||||||
|
import basics.route.ServiceActivity;
|
||||||
|
import basics.route.Start;
|
||||||
|
import basics.route.TourActivities;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
import basics.route.VehicleImpl.NoVehicle;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class CalculatesServiceInsertion implements JobInsertionCalculator{
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(CalculatesServiceInsertion.class);
|
||||||
|
|
||||||
|
private RouteStates routeStates;
|
||||||
|
|
||||||
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
|
private VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
private Start start;
|
||||||
|
|
||||||
|
private End end;
|
||||||
|
|
||||||
|
private Neighborhood neighborhood = new Neighborhood() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areNeighbors(String location1, String location2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void setNeighborhood(Neighborhood neighborhood) {
|
||||||
|
this.neighborhood = neighborhood;
|
||||||
|
logger.info("initialise neighborhood " + neighborhood);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActivityStates(RouteStates actStates){
|
||||||
|
this.routeStates = actStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActivityState state(TourActivity act){
|
||||||
|
return routeStates.getState(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CalculatesServiceInsertion(VehicleRoutingTransportCosts vehicleRoutingTransportCosts, VehicleRoutingActivityCosts vehicleRoutingActivityCosts) {
|
||||||
|
super();
|
||||||
|
this.routingCosts = vehicleRoutingTransportCosts;
|
||||||
|
this.activityCosts = vehicleRoutingActivityCosts;
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=calculatesServiceInsertion]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the marginal cost of inserting job i locally. This is based on the
|
||||||
|
* assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public InsertionData calculate(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
|
||||||
|
if(jobToInsert == null) throw new IllegalStateException("jobToInsert is missing.");
|
||||||
|
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("newVehicle is missing.");
|
||||||
|
|
||||||
|
TourActivities tour = currentRoute.getTourActivities();
|
||||||
|
double bestCost = bestKnownCosts;
|
||||||
|
Service service = (Service)jobToInsert;
|
||||||
|
|
||||||
|
if(routeStates.getRouteState(currentRoute).getLoad() + service.getCapacityDemand() > newVehicle.getCapacity()){
|
||||||
|
return InsertionData.noInsertionFound();
|
||||||
|
}
|
||||||
|
int insertionIndex = InsertionData.NO_INDEX;
|
||||||
|
|
||||||
|
TourActivity deliveryAct2Insert = ServiceActivity.newInstance(service);
|
||||||
|
// TourActivity deliveryAct2Insert = actStates.getActivity(service, true);
|
||||||
|
|
||||||
|
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime);
|
||||||
|
|
||||||
|
TourActivity prevAct = start;
|
||||||
|
double prevCostInOriginalTour = 0.0;
|
||||||
|
int actIndex = 0;
|
||||||
|
for(TourActivity nextAct : tour.getActivities()){
|
||||||
|
double nextCostInOriginalTour = state(nextAct).getCurrentCost();
|
||||||
|
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
|
||||||
|
double mc = calculate(tour, prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, nextCostInOriginalTour - prevCostInOriginalTour);
|
||||||
|
if(mc < bestCost){
|
||||||
|
bestCost = mc;
|
||||||
|
insertionIndex = actIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevCostInOriginalTour = nextCostInOriginalTour;
|
||||||
|
prevAct = nextAct;
|
||||||
|
actIndex++;
|
||||||
|
}
|
||||||
|
End nextAct = end;
|
||||||
|
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
|
||||||
|
double mc = calculate(tour, prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, routeStates.getRouteState(currentRoute).getCosts() - prevCostInOriginalTour);
|
||||||
|
if(mc < bestCost){
|
||||||
|
bestCost = mc;
|
||||||
|
insertionIndex = actIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(insertionIndex == InsertionData.NO_INDEX) {
|
||||||
|
return InsertionData.noInsertionFound();
|
||||||
|
}
|
||||||
|
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
||||||
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
|
return insertionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialiseStartAndEnd(final Vehicle newVehicle,
|
||||||
|
double newVehicleDepartureTime) {
|
||||||
|
if(start == null){
|
||||||
|
start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
|
||||||
|
start.setEndTime(newVehicleDepartureTime);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
start.setLocationId(newVehicle.getLocationId());
|
||||||
|
start.setTheoreticalEarliestOperationStartTime(newVehicle.getEarliestDeparture());
|
||||||
|
start.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
|
||||||
|
start.setEndTime(newVehicleDepartureTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(end == null){
|
||||||
|
end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
end.setLocationId(newVehicle.getLocationId());
|
||||||
|
end.setTheoreticalEarliestOperationStartTime(newVehicleDepartureTime);
|
||||||
|
end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double calculate(TourActivities tour, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle, double bestKnownCosts, double costWithoutNewJob) {
|
||||||
|
|
||||||
|
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
|
||||||
|
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
|
||||||
|
|
||||||
|
double newAct_arrTime = prevAct.getEndTime() + tp_time_prevAct_newAct;
|
||||||
|
double newAct_operationStartTime = Math.max(newAct_arrTime, newAct.getTheoreticalEarliestOperationStartTime());
|
||||||
|
|
||||||
|
double newAct_endTime = newAct_operationStartTime + newAct.getOperationTime();
|
||||||
|
|
||||||
|
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, driver, vehicle);
|
||||||
|
|
||||||
|
if((tp_costs_prevAct_newAct + act_costs_newAct - costWithoutNewJob) > bestKnownCosts){
|
||||||
|
return Double.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle);
|
||||||
|
double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle);
|
||||||
|
|
||||||
|
double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct;
|
||||||
|
double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, driver, vehicle);
|
||||||
|
|
||||||
|
double activityInsertionCosts;
|
||||||
|
|
||||||
|
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct;
|
||||||
|
|
||||||
|
if(totalCosts - costWithoutNewJob > bestKnownCosts){
|
||||||
|
activityInsertionCosts = Double.MAX_VALUE;
|
||||||
|
}
|
||||||
|
if(nextAct_arrTime > getLatestOperationStart(nextAct)){
|
||||||
|
activityInsertionCosts = Double.MAX_VALUE;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
activityInsertionCosts = totalCosts - costWithoutNewJob;
|
||||||
|
}
|
||||||
|
return activityInsertionCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getLatestOperationStart(TourActivity act) {
|
||||||
|
if(state(act) != null){
|
||||||
|
return state(act).getLatestOperationStart();
|
||||||
|
}
|
||||||
|
return act.getTheoreticalLatestOperationStartTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import algorithms.InsertionData.NoInsertionFound;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.Driver;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleImpl.NoVehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class CalculatesServiceInsertionConsideringFixCost implements JobInsertionCalculator{
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(CalculatesServiceInsertionConsideringFixCost.class);
|
||||||
|
|
||||||
|
private final JobInsertionCalculator standardServiceInsertion;
|
||||||
|
|
||||||
|
private double weight_deltaFixCost = 0.5;
|
||||||
|
|
||||||
|
private double solution_completeness_ratio = 0.5;
|
||||||
|
|
||||||
|
private RouteStates routeStates;
|
||||||
|
|
||||||
|
public CalculatesServiceInsertionConsideringFixCost(final JobInsertionCalculator standardInsertionCalculator, RouteStates routeStates) {
|
||||||
|
super();
|
||||||
|
this.standardServiceInsertion = standardInsertionCalculator;
|
||||||
|
this.routeStates = routeStates;
|
||||||
|
logger.info("inialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertionData calculate(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownPrice) {
|
||||||
|
double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert);
|
||||||
|
double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert);
|
||||||
|
double deltaFixCost = (1-solution_completeness_ratio)*relFixCost + solution_completeness_ratio*absFixCost;
|
||||||
|
double fixcost_contribution = weight_deltaFixCost*solution_completeness_ratio*deltaFixCost;
|
||||||
|
if(fixcost_contribution > bestKnownPrice){
|
||||||
|
return InsertionData.noInsertionFound();
|
||||||
|
}
|
||||||
|
InsertionData iData = standardServiceInsertion.calculate(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice);
|
||||||
|
if(iData instanceof NoInsertionFound){
|
||||||
|
return iData;
|
||||||
|
}
|
||||||
|
double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution;
|
||||||
|
InsertionData insertionData = new InsertionData(totalInsertionCost, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), newVehicle, newDriver);
|
||||||
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
|
return insertionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWeightOfFixCost(double weight){
|
||||||
|
weight_deltaFixCost = weight;
|
||||||
|
logger.info("set weightOfFixCostSaving to " + weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings="+weight_deltaFixCost+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSolutionCompletenessRatio(double ratio){
|
||||||
|
solution_completeness_ratio = ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job) {
|
||||||
|
double load = routeStates.getRouteState(route).getLoad() + job.getCapacityDemand();
|
||||||
|
double currentFix = 0.0;
|
||||||
|
if(route.getVehicle() != null){
|
||||||
|
if(!(route.getVehicle() instanceof NoVehicle)){
|
||||||
|
currentFix += route.getVehicle().getType().vehicleCostParams.fix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(newVehicle.getCapacity() < load){
|
||||||
|
return Double.MAX_VALUE;
|
||||||
|
}
|
||||||
|
return newVehicle.getType().vehicleCostParams.fix - currentFix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job) {
|
||||||
|
int currentLoad = routeStates.getRouteState(route).getLoad();
|
||||||
|
double load = currentLoad + job.getCapacityDemand();
|
||||||
|
double currentRelFix = 0.0;
|
||||||
|
if(route.getVehicle() != null){
|
||||||
|
if(!(route.getVehicle() instanceof NoVehicle)){
|
||||||
|
currentRelFix += route.getVehicle().getType().vehicleCostParams.fix*currentLoad/route.getVehicle().getCapacity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(newVehicle.getCapacity() < load){
|
||||||
|
return Double.MAX_VALUE;
|
||||||
|
}
|
||||||
|
double relativeFixCost = newVehicle.getType().vehicleCostParams.fix*(load/newVehicle.getCapacity()) - currentRelFix;
|
||||||
|
return relativeFixCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,356 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.Neighborhood;
|
||||||
|
|
||||||
|
import algorithms.RouteStates.ActivityState;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.Driver;
|
||||||
|
import basics.route.End;
|
||||||
|
import basics.route.Start;
|
||||||
|
import basics.route.TourActivities;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
import basics.route.VehicleImpl.NoVehicle;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalculator{
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(CalculatesServiceInsertionOnRouteLevel.class);
|
||||||
|
|
||||||
|
private final VehicleRoutingTransportCosts transportCosts;
|
||||||
|
|
||||||
|
private final VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
private AuxilliaryCostCalculator auxilliaryPathCostCalculator;
|
||||||
|
|
||||||
|
private RouteStates routeStates;
|
||||||
|
|
||||||
|
private int nuOfActsForwardLooking = 0;
|
||||||
|
|
||||||
|
private int memorySize = 2;
|
||||||
|
|
||||||
|
private Start start;
|
||||||
|
|
||||||
|
private End end;
|
||||||
|
|
||||||
|
private Neighborhood neighborhood = new Neighborhood() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areNeighbors(String location1, String location2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void setNeighborhood(Neighborhood neighborhood) {
|
||||||
|
this.neighborhood = neighborhood;
|
||||||
|
logger.info("initialise neighborhood " + neighborhood);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMemorySize(int memorySize) {
|
||||||
|
this.memorySize = memorySize;
|
||||||
|
logger.info("set [solutionMemory="+memorySize+"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public CalculatesServiceInsertionOnRouteLevel(VehicleRoutingTransportCosts vehicleRoutingCosts, VehicleRoutingActivityCosts costFunc) {
|
||||||
|
super();
|
||||||
|
this.transportCosts = vehicleRoutingCosts;
|
||||||
|
this.activityCosts = costFunc;
|
||||||
|
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(transportCosts, activityCosts);
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActivityStates(RouteStates actStates){
|
||||||
|
this.routeStates = actStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActivityState state(TourActivity act){
|
||||||
|
return routeStates.getState(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setNuOfActsForwardLooking(int nOfActsForwardLooking) {
|
||||||
|
this.nuOfActsForwardLooking = nOfActsForwardLooking;
|
||||||
|
logger.info("set [forwardLooking="+nOfActsForwardLooking+"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=calculatesServiceInsertionOnRouteLevel][solutionMemory="+memorySize+"][forwardLooking="+nuOfActsForwardLooking+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the insertion costs of job i on route level (which is based on the assumption that inserting job i does not only
|
||||||
|
* have local effects but affects the entire route).
|
||||||
|
* Calculation is conducted by two steps. In the first step, promising insertion positions are identified by appromiximating their
|
||||||
|
* marginal insertion cost. In the second step, marginal cost of the best M positions are calculated exactly.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public InsertionData calculate(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double best_known_insertion_costs) {
|
||||||
|
if(jobToInsert == null) throw new IllegalStateException("job is null. cannot calculate the insertion of a null-job.");
|
||||||
|
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("no vehicle given. set para vehicle!");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* map that memorizes the costs with newVehicle, which is a cost-snapshot at tour-activities.
|
||||||
|
*/
|
||||||
|
Map<TourActivity,Double> activity2costWithNewVehicle = new HashMap<TourActivity,Double>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* priority queue that stores insertion-data by insertion-costs in ascending order.
|
||||||
|
*/
|
||||||
|
PriorityQueue<InsertionData> bestInsertionsQueue = new PriorityQueue<InsertionData>(Math.max(2, currentRoute.getTourActivities().getActivities().size()), getComparator());
|
||||||
|
|
||||||
|
TourActivities tour = currentRoute.getTourActivities();
|
||||||
|
double best_insertion_costs = best_known_insertion_costs;
|
||||||
|
Service service = (Service)jobToInsert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pre-check whether vehicle-capacity of new vehicle is sufficient to load service.
|
||||||
|
*/
|
||||||
|
if(routeStates.getRouteState(currentRoute).getLoad() + service.getCapacityDemand() > newVehicle.getCapacity()){
|
||||||
|
return InsertionData.noInsertionFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* some inis
|
||||||
|
*/
|
||||||
|
TourActivity serviceAct2Insert = routeStates.getActivity(service, true);
|
||||||
|
int best_insertion_index = InsertionData.NO_INDEX;
|
||||||
|
|
||||||
|
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime);
|
||||||
|
|
||||||
|
TourActivity prevAct = start;
|
||||||
|
int actIndex = 0;
|
||||||
|
double sumOf_prevCosts_newVehicle = 0.0;
|
||||||
|
double prevActDepTime_newVehicle = start.getEndTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inserting serviceAct2Insert in route r={0,1,...,i-1,i,j,j+1,...,n(r),n(r)+1}
|
||||||
|
* i=prevAct
|
||||||
|
* j=nextAct
|
||||||
|
* k=serviceAct2Insert
|
||||||
|
*/
|
||||||
|
for(TourActivity nextAct : tour.getActivities()){
|
||||||
|
if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){
|
||||||
|
/**
|
||||||
|
* builds a path on this route forwardPath={i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking}
|
||||||
|
*/
|
||||||
|
List<TourActivity> path = new ArrayList<TourActivity>();
|
||||||
|
path.add(prevAct); path.add(serviceAct2Insert); path.add(nextAct);
|
||||||
|
if(nuOfActsForwardLooking > 0){ path.addAll(getForwardLookingPath(currentRoute,actIndex)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculates the path costs with new vehicle, c(forwardPath,newVehicle).
|
||||||
|
*/
|
||||||
|
double forwardPathCost_newVehicle = auxilliaryPathCostCalculator.costOfPath(path, prevActDepTime_newVehicle, newDriver, newVehicle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle)
|
||||||
|
*/
|
||||||
|
double insertion_cost_approximation = sumOf_prevCosts_newVehicle + forwardPathCost_newVehicle - pathCost_oldVehicle(currentRoute,path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* memorize it in insertion-queue
|
||||||
|
*/
|
||||||
|
if(insertion_cost_approximation < best_known_insertion_costs){
|
||||||
|
bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation, InsertionData.NO_INDEX, actIndex, newVehicle, newDriver));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculate transport and activity costs with new vehicle (without inserting k)
|
||||||
|
*/
|
||||||
|
double transportCost_prevAct_nextAct_newVehicle = transportCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), prevActDepTime_newVehicle, newDriver, newVehicle);
|
||||||
|
double transportTime_prevAct_nextAct_newVehicle = transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActDepTime_newVehicle, newDriver, newVehicle);
|
||||||
|
double arrTime_nextAct_newVehicle = prevActDepTime_newVehicle + transportTime_prevAct_nextAct_newVehicle;
|
||||||
|
double activityCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct_newVehicle, newDriver, newVehicle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* memorize transport and activity costs with new vehicle without inserting k
|
||||||
|
*/
|
||||||
|
sumOf_prevCosts_newVehicle += transportCost_prevAct_nextAct_newVehicle + activityCost_nextAct;
|
||||||
|
activity2costWithNewVehicle.put(nextAct, sumOf_prevCosts_newVehicle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* departure time at nextAct with new vehicle
|
||||||
|
*/
|
||||||
|
double depTime_nextAct_newVehicle = Math.max(arrTime_nextAct_newVehicle, nextAct.getTheoreticalEarliestOperationStartTime()) + nextAct.getOperationTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set previous to next
|
||||||
|
*/
|
||||||
|
prevAct = nextAct;
|
||||||
|
prevActDepTime_newVehicle = depTime_nextAct_newVehicle;
|
||||||
|
|
||||||
|
actIndex++;
|
||||||
|
}
|
||||||
|
End nextAct = end;
|
||||||
|
if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculates the path costs with new vehicle, c(forwardPath,newVehicle).
|
||||||
|
*/
|
||||||
|
List<TourActivity> path = Arrays.asList(prevAct,serviceAct2Insert,end);
|
||||||
|
double forwardPathCost_newVehicle = auxilliaryPathCostCalculator.costOfPath(path, prevActDepTime_newVehicle, newDriver, newVehicle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle)
|
||||||
|
*/
|
||||||
|
double insertion_cost_approximation = sumOf_prevCosts_newVehicle + forwardPathCost_newVehicle - pathCost_oldVehicle(currentRoute,path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* memorize it in insertion-queue
|
||||||
|
*/
|
||||||
|
if(insertion_cost_approximation < best_known_insertion_costs){
|
||||||
|
bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation,InsertionData.NO_INDEX, actIndex, newVehicle, newDriver));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the above calculations approximate insertion costs. now calculate the exact insertion costs for the most promising (according to the approximation)
|
||||||
|
* insertion positions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
for(int i=0;i<memorySize;i++){
|
||||||
|
InsertionData data = bestInsertionsQueue.poll();
|
||||||
|
if(data == null){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* build tour with new activity.
|
||||||
|
*/
|
||||||
|
List<TourActivity> wholeTour = new ArrayList<TourActivity>();
|
||||||
|
wholeTour.add(start);
|
||||||
|
wholeTour.addAll(currentRoute.getTourActivities().getActivities());
|
||||||
|
wholeTour.add(end);
|
||||||
|
wholeTour.add(data.getDeliveryInsertionIndex()+1, serviceAct2Insert);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compute cost-diff of tour with and without new activity --> insertion_costs
|
||||||
|
*/
|
||||||
|
double insertion_costs = auxilliaryPathCostCalculator.costOfPath(wholeTour, start.getEndTime(), newDriver, newVehicle) - routeStates.getRouteState(currentRoute).getCosts();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if better than best known, make it the best known
|
||||||
|
*/
|
||||||
|
if(insertion_costs < best_insertion_costs){
|
||||||
|
best_insertion_index = data.getDeliveryInsertionIndex();
|
||||||
|
best_insertion_costs = insertion_costs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(best_insertion_index == InsertionData.NO_INDEX) return InsertionData.noInsertionFound();
|
||||||
|
return new InsertionData(best_insertion_costs, InsertionData.NO_INDEX, best_insertion_index, newVehicle, newDriver);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initialize start and end of tour.
|
||||||
|
*
|
||||||
|
* @param newVehicle
|
||||||
|
* @param newVehicleDepartureTime
|
||||||
|
*/
|
||||||
|
private void initialiseStartAndEnd(final Vehicle newVehicle, double newVehicleDepartureTime) {
|
||||||
|
if(start == null){
|
||||||
|
start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
|
||||||
|
start.setEndTime(newVehicleDepartureTime);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
start.setLocationId(newVehicle.getLocationId());
|
||||||
|
start.setTheoreticalEarliestOperationStartTime(newVehicle.getEarliestDeparture());
|
||||||
|
start.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
|
||||||
|
start.setEndTime(newVehicleDepartureTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(end == null){
|
||||||
|
end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
end.setLocationId(newVehicle.getLocationId());
|
||||||
|
end.setTheoreticalEarliestOperationStartTime(newVehicleDepartureTime);
|
||||||
|
end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double pathCost_oldVehicle(VehicleRoute vehicleRoute, List<TourActivity> path) {
|
||||||
|
TourActivity act = path.get(path.size()-1);
|
||||||
|
if(act instanceof End){
|
||||||
|
return routeStates.getRouteState(vehicleRoute).getCosts();
|
||||||
|
}
|
||||||
|
return state(act).getCurrentCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the path or the partial route r_partial = {j+1,j+2,...,j+nuOfActsForwardLooking}
|
||||||
|
*
|
||||||
|
* @param route
|
||||||
|
* @param actIndex
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<TourActivity> getForwardLookingPath(VehicleRoute route, int actIndex) {
|
||||||
|
List<TourActivity> forwardLookingPath = new ArrayList<TourActivity>();
|
||||||
|
int nuOfActsInPath = 0;
|
||||||
|
int index = actIndex + 1;
|
||||||
|
while(index < route.getTourActivities().getActivities().size() && nuOfActsInPath < nuOfActsForwardLooking){
|
||||||
|
forwardLookingPath.add(route.getTourActivities().getActivities().get(index));
|
||||||
|
index++;
|
||||||
|
nuOfActsInPath++;
|
||||||
|
}
|
||||||
|
if(nuOfActsInPath < nuOfActsForwardLooking){
|
||||||
|
forwardLookingPath.add(route.getEnd());
|
||||||
|
}
|
||||||
|
return forwardLookingPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a comparator to sort insertion-data in insertionQueue in ascending order according insertion costs.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private Comparator<InsertionData> getComparator() {
|
||||||
|
return new Comparator<InsertionData>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(InsertionData o1, InsertionData o2) {
|
||||||
|
if(o1.getInsertionCost() < o2.getInsertionCost()){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.Driver;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCalculator{
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(CalculatesServiceInsertionWithTimeScheduling.class);
|
||||||
|
|
||||||
|
private JobInsertionCalculator jic;
|
||||||
|
|
||||||
|
private Random random = new Random();
|
||||||
|
|
||||||
|
private int nOfDepartureTimes = 3;
|
||||||
|
|
||||||
|
private double timeSlice = 900.0;
|
||||||
|
|
||||||
|
public CalculatesServiceInsertionWithTimeScheduling(JobInsertionCalculator jic, double timeSlice, int neighbors) {
|
||||||
|
super();
|
||||||
|
this.jic = jic;
|
||||||
|
this.timeSlice = timeSlice;
|
||||||
|
this.nOfDepartureTimes = neighbors;
|
||||||
|
log.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=calculatesServiceInsertionWithTimeScheduling][timeSlice="+timeSlice+"][#timeSlice="+nOfDepartureTimes+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertionData calculate(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
|
||||||
|
List<Double> vehicleDepartureTimes = new ArrayList<Double>();
|
||||||
|
double currentStart;
|
||||||
|
if(currentRoute.getStart() == null){
|
||||||
|
currentStart = newVehicleDepartureTime;
|
||||||
|
}
|
||||||
|
else currentStart = currentRoute.getStart().getEndTime();
|
||||||
|
|
||||||
|
vehicleDepartureTimes.add(currentStart);
|
||||||
|
double earliestDeparture = newVehicle.getEarliestDeparture();
|
||||||
|
double latestEnd = newVehicle.getLatestArrival();
|
||||||
|
|
||||||
|
for(int i=0;i<nOfDepartureTimes;i++){
|
||||||
|
double neighborStartTime_earlier = currentStart - (i+1)*timeSlice;
|
||||||
|
if(neighborStartTime_earlier > earliestDeparture) vehicleDepartureTimes.add(neighborStartTime_earlier);
|
||||||
|
double neighborStartTime_later = currentStart + (i+1)*timeSlice;
|
||||||
|
if(neighborStartTime_later < latestEnd) vehicleDepartureTimes.add(neighborStartTime_later);
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertionData bestIData = null;
|
||||||
|
for(Double departureTime : vehicleDepartureTimes){
|
||||||
|
InsertionData iData = jic.calculate(currentRoute, jobToInsert, newVehicle, departureTime, newDriver, bestKnownScore);
|
||||||
|
if(bestIData == null) bestIData = iData;
|
||||||
|
else if(iData.getInsertionCost() < bestIData.getInsertionCost()){
|
||||||
|
iData.setVehicleDepartureTime(departureTime);
|
||||||
|
bestIData = iData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// log.info(bestIData);
|
||||||
|
return bestIData;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import algorithms.InsertionData.NoInsertionFound;
|
||||||
|
import algorithms.VehicleFleetManager.TypeKey;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.Driver;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleImpl.NoVehicle;
|
||||||
|
import basics.route.VehicleImpl.VehicleType;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class CalculatesVehTypeDepServiceInsertion implements JobInsertionCalculator{
|
||||||
|
|
||||||
|
private Logger logger = Logger.getLogger(CalculatesVehTypeDepServiceInsertion.class);
|
||||||
|
|
||||||
|
private final VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
|
private final JobInsertionCalculator insertionCalculator;
|
||||||
|
|
||||||
|
public CalculatesVehTypeDepServiceInsertion(final VehicleFleetManager fleetManager, final JobInsertionCalculator jobInsertionCalc) {
|
||||||
|
this.fleetManager = fleetManager;
|
||||||
|
this.insertionCalculator = jobInsertionCalc;
|
||||||
|
logger.info("inialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=vehicleTypeDependentServiceInsertion]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public InsertionData calculate(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle vehicle, double newVehicleDepartureTime, final Driver driver, final double bestKnownCost) {
|
||||||
|
Vehicle selectedVehicle = currentRoute.getVehicle();
|
||||||
|
Driver selectedDriver = currentRoute.getDriver();
|
||||||
|
InsertionData bestIData = InsertionData.noInsertionFound();
|
||||||
|
double bestKnownCost_ = bestKnownCost;
|
||||||
|
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
||||||
|
if(!(selectedVehicle instanceof NoVehicle)) relevantVehicles.add(selectedVehicle);
|
||||||
|
for(TypeKey typeKey : fleetManager.getAvailableVehicleTypes()){
|
||||||
|
if(!(currentRoute.getVehicle() instanceof NoVehicle)){
|
||||||
|
TypeKey key = makeTypeKey(currentRoute.getVehicle().getType(),currentRoute.getVehicle().getLocationId());
|
||||||
|
if(typeKey.equals(key)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
relevantVehicles.add(fleetManager.getEmptyVehicle(typeKey));
|
||||||
|
}
|
||||||
|
for(Vehicle v : relevantVehicles){
|
||||||
|
double depTime = v.getEarliestDeparture();
|
||||||
|
InsertionData iData = insertionCalculator.calculate(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
|
||||||
|
if(iData instanceof NoInsertionFound) {
|
||||||
|
if(bestIData instanceof NoInsertionFound) bestIData = iData;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(iData.getInsertionCost() < bestKnownCost_){
|
||||||
|
bestIData = iData;
|
||||||
|
bestKnownCost_ = iData.getInsertionCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestIData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeKey makeTypeKey(VehicleType type, String locationId) {
|
||||||
|
return new TypeKey(type,locationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
268
jsprit-core/src/main/java/algorithms/CalculatorBuilder.java
Normal file
268
jsprit-core/src/main/java/algorithms/CalculatorBuilder.java
Normal file
|
|
@ -0,0 +1,268 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.configuration.XMLConfiguration;
|
||||||
|
|
||||||
|
import util.NeighborhoodImpl;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblem.FleetComposition;
|
||||||
|
import basics.algo.InsertionListener;
|
||||||
|
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
||||||
|
import basics.algo.VehicleRoutingAlgorithmListeners.Priority;
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CalculatorBuilder {
|
||||||
|
|
||||||
|
private static class CalculatorPlusListeners {
|
||||||
|
|
||||||
|
private JobInsertionCalculator calculator;
|
||||||
|
|
||||||
|
public JobInsertionCalculator getCalculator() {
|
||||||
|
return calculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PrioritizedVRAListener> algorithmListener = new ArrayList<PrioritizedVRAListener>();
|
||||||
|
private List<InsertionListener> insertionListener = new ArrayList<InsertionListener>();
|
||||||
|
|
||||||
|
public CalculatorPlusListeners(JobInsertionCalculator calculator) {
|
||||||
|
super();
|
||||||
|
this.calculator = calculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PrioritizedVRAListener> getAlgorithmListener() {
|
||||||
|
return algorithmListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<InsertionListener> getInsertionListener() {
|
||||||
|
return insertionListener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<InsertionListener> insertionListeners;
|
||||||
|
|
||||||
|
private List<PrioritizedVRAListener> algorithmListeners;
|
||||||
|
|
||||||
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
|
private RouteStates activityStates;
|
||||||
|
|
||||||
|
private boolean local = true;
|
||||||
|
|
||||||
|
private int forwardLooking = 0;
|
||||||
|
|
||||||
|
private int memory = 1;
|
||||||
|
|
||||||
|
private boolean considerFixedCost = false;
|
||||||
|
|
||||||
|
private double weightOfFixedCost = 0;
|
||||||
|
|
||||||
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
|
private boolean timeScheduling;
|
||||||
|
|
||||||
|
private double timeSlice;
|
||||||
|
|
||||||
|
private int neighbors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the builder.
|
||||||
|
*
|
||||||
|
* <p>Some calculators require information from the overall algorithm or the higher-level insertion procedure. Thus listeners inform them.
|
||||||
|
* These listeners are cached in the according list and can thus be added when its time to add them.
|
||||||
|
*
|
||||||
|
* @param insertionListeners
|
||||||
|
* @param algorithmListeners
|
||||||
|
*/
|
||||||
|
public CalculatorBuilder(List<InsertionListener> insertionListeners, List<PrioritizedVRAListener> algorithmListeners) {
|
||||||
|
super();
|
||||||
|
this.insertionListeners = insertionListeners;
|
||||||
|
this.algorithmListeners = algorithmListeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets activityStates. MUST be set.
|
||||||
|
*
|
||||||
|
* @param activityStates
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public CalculatorBuilder setActivityStates(RouteStates activityStates){
|
||||||
|
this.activityStates = activityStates;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets routingProblem. MUST be set.
|
||||||
|
*
|
||||||
|
* @param vehicleRoutingProblem
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public CalculatorBuilder setVehicleRoutingProblem(VehicleRoutingProblem vehicleRoutingProblem){
|
||||||
|
this.vrp = vehicleRoutingProblem;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets fleetManager. MUST be set.
|
||||||
|
*
|
||||||
|
* @param fleetManager
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public CalculatorBuilder setVehicleFleetManager(VehicleFleetManager fleetManager){
|
||||||
|
this.fleetManager = fleetManager;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a flag to build a calculator based on local calculations.
|
||||||
|
*
|
||||||
|
* <p>Insertion of a job and job-activity is evaluated based on the previous and next activity.
|
||||||
|
*/
|
||||||
|
public void setLocalLevel(){
|
||||||
|
local = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a flag to build a calculator that evaluates job insertion on route-level.
|
||||||
|
*
|
||||||
|
* @param forwardLooking
|
||||||
|
* @param memory
|
||||||
|
*/
|
||||||
|
public void setRouteLevel(int forwardLooking, int memory){
|
||||||
|
local = false;
|
||||||
|
this.forwardLooking = forwardLooking;
|
||||||
|
this.memory = memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a flag to consider also fixed-cost when evaluating the insertion of a job. The weight of the fixed-cost can be determined by setting
|
||||||
|
* weightofFixedCosts.
|
||||||
|
*
|
||||||
|
* @param weightOfFixedCosts
|
||||||
|
*/
|
||||||
|
public void considerFixedCosts(double weightOfFixedCosts){
|
||||||
|
considerFixedCost = true;
|
||||||
|
this.weightOfFixedCost = weightOfFixedCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void experimentalTimeScheduler(double timeSlice, int neighbors){
|
||||||
|
timeScheduling = true;
|
||||||
|
this.timeSlice = timeSlice;
|
||||||
|
this.neighbors = neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the jobInsertionCalculator.
|
||||||
|
*
|
||||||
|
* @return jobInsertionCalculator.
|
||||||
|
* @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null.
|
||||||
|
*/
|
||||||
|
public JobInsertionCalculator build(){
|
||||||
|
if(vrp == null) throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))");
|
||||||
|
if(activityStates == null) throw new IllegalStateException("activity states is null, but is must be set (this.setActivityStates(states))");
|
||||||
|
if(fleetManager == null) throw new IllegalStateException("fleetManager is null, but it must be set (this.setVehicleFleetManager(fleetManager))");
|
||||||
|
JobInsertionCalculator baseCalculator = null;
|
||||||
|
CalculatorPlusListeners standardLocal = null;
|
||||||
|
if(local){
|
||||||
|
standardLocal = createStandardLocal(vrp, activityStates);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
standardLocal = createStandardRoute(vrp, activityStates,forwardLooking,memory);
|
||||||
|
}
|
||||||
|
baseCalculator = standardLocal.getCalculator();
|
||||||
|
addAlgorithmListeners(standardLocal.getAlgorithmListener());
|
||||||
|
addInsertionListeners(standardLocal.getInsertionListener());
|
||||||
|
if(considerFixedCost){
|
||||||
|
CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, activityStates, weightOfFixedCost);
|
||||||
|
baseCalculator = withFixed.getCalculator();
|
||||||
|
addAlgorithmListeners(withFixed.getAlgorithmListener());
|
||||||
|
addInsertionListeners(withFixed.getInsertionListener());
|
||||||
|
}
|
||||||
|
if(timeScheduling){
|
||||||
|
baseCalculator = new CalculatesServiceInsertionWithTimeScheduling(baseCalculator,timeSlice,neighbors);
|
||||||
|
}
|
||||||
|
return createFinalInsertion(fleetManager, baseCalculator, activityStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addInsertionListeners(List<InsertionListener> list) {
|
||||||
|
for(InsertionListener iL : list){
|
||||||
|
insertionListeners.add(iL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAlgorithmListeners(List<PrioritizedVRAListener> list) {
|
||||||
|
for(PrioritizedVRAListener aL : list){
|
||||||
|
algorithmListeners.add(aL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, RouteStates activityStates){
|
||||||
|
JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), vrp.getActivityCosts());
|
||||||
|
((CalculatesServiceInsertion) standardServiceInsertion).setActivityStates(activityStates);
|
||||||
|
((CalculatesServiceInsertion) standardServiceInsertion).setNeighborhood(vrp.getNeighborhood());
|
||||||
|
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(standardServiceInsertion);
|
||||||
|
|
||||||
|
return calcPlusListeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCalculator baseCalculator, RouteStates activityStates, double weightOfFixedCosts){
|
||||||
|
final CalculatesServiceInsertionConsideringFixCost withFixCost = new CalculatesServiceInsertionConsideringFixCost(baseCalculator, activityStates);
|
||||||
|
withFixCost.setWeightOfFixCost(weightOfFixedCosts);
|
||||||
|
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost);
|
||||||
|
calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost));
|
||||||
|
return calcPlusListeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CalculatorPlusListeners createStandardRoute(VehicleRoutingProblem vrp, RouteStates activityStates, int forwardLooking, int solutionMemory){
|
||||||
|
int after = forwardLooking;
|
||||||
|
JobInsertionCalculator jobInsertionCalculator = new CalculatesServiceInsertionOnRouteLevel(vrp.getTransportCosts(), vrp.getActivityCosts());
|
||||||
|
((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setNuOfActsForwardLooking(after);
|
||||||
|
((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setMemorySize(solutionMemory);
|
||||||
|
((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setNeighborhood(vrp.getNeighborhood());
|
||||||
|
((CalculatesServiceInsertionOnRouteLevel) jobInsertionCalculator).setActivityStates(activityStates);
|
||||||
|
CalculatorPlusListeners calcPlusListener = new CalculatorPlusListeners(jobInsertionCalculator);
|
||||||
|
return calcPlusListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JobInsertionCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCalculator baseCalc, RouteStates routeStates){
|
||||||
|
return new CalculatesVehTypeDepServiceInsertion(fleetManager, baseCalc);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.algo.InsertionStartsListener;
|
||||||
|
import basics.algo.JobInsertedListener;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class ConfigureFixCostCalculator implements InsertionStartsListener, JobInsertedListener{
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(ConfigureFixCostCalculator.class);
|
||||||
|
|
||||||
|
VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
|
CalculatesServiceInsertionConsideringFixCost calcConsideringFix;
|
||||||
|
|
||||||
|
public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, CalculatesServiceInsertionConsideringFixCost calcConsideringFix) {
|
||||||
|
super();
|
||||||
|
this.vrp = vrp;
|
||||||
|
this.calcConsideringFix = calcConsideringFix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=configureFixCostCalculator]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionStarts(Collection<VehicleRoute> routes, int nOfJobs2Recreate) {
|
||||||
|
double completenessRatio = (1-((double)nOfJobs2Recreate/(double)vrp.getJobs().values().size()));
|
||||||
|
calcConsideringFix.setSolutionCompletenessRatio(completenessRatio);
|
||||||
|
// log.debug("initialise completenessRatio to " + completenessRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informJobInserted(int nOfJobsStill2Recreate, Job job2insert, VehicleRoute insertedIn) {
|
||||||
|
double completenessRatio = (1-((double)nOfJobsStill2Recreate/(double)vrp.getJobs().values().size()));
|
||||||
|
calcConsideringFix.setSolutionCompletenessRatio(completenessRatio);
|
||||||
|
// log.debug("set completenessRatio to " + completenessRatio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
/* *********************************************************************** *
|
||||||
|
* project: org.matsim.*
|
||||||
|
* IniSolution.java
|
||||||
|
* *
|
||||||
|
* *********************************************************************** *
|
||||||
|
* *
|
||||||
|
* copyright : (C) 2011 by the members listed in the COPYING, *
|
||||||
|
* LICENSE and WARRANTY file. *
|
||||||
|
* email : info at matsim dot org *
|
||||||
|
* *
|
||||||
|
* *********************************************************************** *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* See also COPYING, LICENSE and WARRANTY file *
|
||||||
|
* *
|
||||||
|
* *********************************************************************** */
|
||||||
|
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.route.DriverImpl;
|
||||||
|
import basics.route.TourActivities;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class CreateInitialSolution implements InitialSolutionFactory {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(CreateInitialSolution.class);
|
||||||
|
|
||||||
|
private final AbstractInsertionStrategy insertion;
|
||||||
|
|
||||||
|
private boolean generateAsMuchAsRoutesAsVehiclesExist = false;
|
||||||
|
|
||||||
|
public void setGenerateAsMuchAsRoutesAsVehiclesExist(boolean generateAsMuchAsRoutesAsVehiclesExist) {
|
||||||
|
this.generateAsMuchAsRoutesAsVehiclesExist = generateAsMuchAsRoutesAsVehiclesExist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CreateInitialSolution(AbstractInsertionStrategy insertion) {
|
||||||
|
super();
|
||||||
|
this.insertion = insertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleRoutingProblemSolution createInitialSolution(final VehicleRoutingProblem vrp) {
|
||||||
|
logger.info("create initial solution.");
|
||||||
|
List<VehicleRoute> vehicleRoutes = new ArrayList<VehicleRoute>();
|
||||||
|
if(generateAsMuchAsRoutesAsVehiclesExist){
|
||||||
|
for(Vehicle vehicle : vrp.getVehicles()){
|
||||||
|
vehicleRoutes.add(VehicleRoute.newInstance(TourActivities.emptyTour(), DriverImpl.noDriver(), vehicle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insertion.run(vehicleRoutes, getUnassignedJobs(vrp), Double.MAX_VALUE);
|
||||||
|
double totalCost = getTotalCost(vehicleRoutes);
|
||||||
|
logger.info("creation done");
|
||||||
|
return new VehicleRoutingProblemSolution(vehicleRoutes, totalCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getTotalCost(List<VehicleRoute> serviceProviders) {
|
||||||
|
double c = 0.0;
|
||||||
|
for(VehicleRoute a : serviceProviders){
|
||||||
|
c += a.getCost();
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Job> getUnassignedJobs(VehicleRoutingProblem vrp) {
|
||||||
|
List<Job> jobs = new ArrayList<Job>(vrp.getJobs().values());
|
||||||
|
return jobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
56
jsprit-core/src/main/java/algorithms/FindCheaperVehicle.java
Normal file
56
jsprit-core/src/main/java/algorithms/FindCheaperVehicle.java
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import basics.algo.InsertionStartsListener;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class FindCheaperVehicle implements InsertionStartsListener{
|
||||||
|
|
||||||
|
FindCheaperVehicleAlgo findCheaperVehicle;
|
||||||
|
|
||||||
|
public FindCheaperVehicle(FindCheaperVehicleAlgo findCheaperVehicle) {
|
||||||
|
super();
|
||||||
|
this.findCheaperVehicle = findCheaperVehicle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2Recreate) {
|
||||||
|
List<VehicleRoute> newRoutes = new ArrayList<VehicleRoute>();
|
||||||
|
for(VehicleRoute route : vehicleRoutes){
|
||||||
|
if(route.isEmpty()) continue;
|
||||||
|
VehicleRoute cheaperRoute = findCheaperVehicle.runAndGetVehicleRoute(route);
|
||||||
|
newRoutes.add(cheaperRoute);
|
||||||
|
}
|
||||||
|
vehicleRoutes.clear();
|
||||||
|
vehicleRoutes.addAll(newRoutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=findCheaperVehicle]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
115
jsprit-core/src/main/java/algorithms/FindCheaperVehicleAlgo.java
Normal file
115
jsprit-core/src/main/java/algorithms/FindCheaperVehicleAlgo.java
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import algorithms.VehicleFleetManager.TypeKey;
|
||||||
|
import basics.route.TourActivities;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
import basics.route.VehicleImpl.NoVehicle;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class FindCheaperVehicleAlgo {
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(FindCheaperVehicleAlgo.class);
|
||||||
|
|
||||||
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
|
private VehicleRouteUpdater tourStateCalculator;
|
||||||
|
|
||||||
|
private AuxilliaryCostCalculator auxilliaryCostCalculator;
|
||||||
|
|
||||||
|
private double weightFixCosts = 1.0;
|
||||||
|
|
||||||
|
private RouteStates states;
|
||||||
|
|
||||||
|
public void setWeightFixCosts(double weightFixCosts) {
|
||||||
|
this.weightFixCosts = weightFixCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStates(RouteStates states) {
|
||||||
|
this.states = states;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FindCheaperVehicleAlgo(VehicleFleetManager fleetManager, VehicleRouteUpdater tourStateCalculator, AuxilliaryCostCalculator auxilliaryCostCalculator) {
|
||||||
|
super();
|
||||||
|
this.fleetManager = fleetManager;
|
||||||
|
this.tourStateCalculator = tourStateCalculator;
|
||||||
|
this.auxilliaryCostCalculator = auxilliaryCostCalculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public VehicleRoute runAndGetVehicleRoute(VehicleRoute vehicleRoute) {
|
||||||
|
if(vehicleRoute.getVehicle() instanceof NoVehicle){
|
||||||
|
return vehicleRoute;
|
||||||
|
}
|
||||||
|
if(vehicleRoute.getTourActivities() == null || vehicleRoute.getVehicle() == null){
|
||||||
|
return vehicleRoute;
|
||||||
|
}
|
||||||
|
Collection<TypeKey> availableVehicleTypes = fleetManager.getAvailableVehicleTypes(new TypeKey(vehicleRoute.getVehicle().getType(),vehicleRoute.getVehicle().getLocationId()));
|
||||||
|
double bestSaving = 0.0;
|
||||||
|
Vehicle bestVehicle = null;
|
||||||
|
List<TourActivity> path = new ArrayList<TourActivity>();
|
||||||
|
path.add(vehicleRoute.getStart());
|
||||||
|
path.addAll(vehicleRoute.getTourActivities().getActivities());
|
||||||
|
path.add(vehicleRoute.getEnd());
|
||||||
|
|
||||||
|
for(TypeKey vehicleType : availableVehicleTypes){
|
||||||
|
Vehicle vehicle = fleetManager.getEmptyVehicle(vehicleType);
|
||||||
|
if(vehicle.getType().typeId.equals(vehicleRoute.getVehicle().getType().typeId)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(states.getRouteState(vehicleRoute).getLoad() <= vehicle.getCapacity()){
|
||||||
|
double fixCostSaving = vehicleRoute.getVehicle().getType().vehicleCostParams.fix - vehicle.getType().vehicleCostParams.fix;
|
||||||
|
double departureTime = vehicleRoute.getStart().getEndTime();
|
||||||
|
double newCost = auxilliaryCostCalculator.costOfPath(path, departureTime, vehicleRoute.getDriver(), vehicle);
|
||||||
|
double varCostSaving = states.getRouteState(vehicleRoute).getCosts() - newCost;
|
||||||
|
double totalCostSaving = varCostSaving + weightFixCosts*fixCostSaving;
|
||||||
|
if(totalCostSaving > bestSaving){
|
||||||
|
bestSaving = totalCostSaving;
|
||||||
|
bestVehicle = vehicle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(bestVehicle != null){
|
||||||
|
try{
|
||||||
|
fleetManager.unlock(vehicleRoute.getVehicle());
|
||||||
|
fleetManager.lock(bestVehicle);
|
||||||
|
}
|
||||||
|
catch(IllegalStateException e){
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
TourActivities newTour = TourActivities.copyOf(vehicleRoute.getTourActivities());
|
||||||
|
tourStateCalculator.updateRoute(vehicleRoute);
|
||||||
|
return VehicleRoute.newInstance(newTour,vehicleRoute.getDriver(),bestVehicle);
|
||||||
|
}
|
||||||
|
return vehicleRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
207
jsprit-core/src/main/java/algorithms/GendreauPostOpt.java
Normal file
207
jsprit-core/src/main/java/algorithms/GendreauPostOpt.java
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.SearchStrategyModule;
|
||||||
|
import basics.algo.SearchStrategyModuleListener;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
import basics.route.TourActivity.JobActivity;
|
||||||
|
|
||||||
|
import util.RandomNumberGeneration;
|
||||||
|
|
||||||
|
final class GendreauPostOpt implements SearchStrategyModule{
|
||||||
|
|
||||||
|
private final static Logger log = Logger.getLogger(GendreauPostOpt.class);
|
||||||
|
|
||||||
|
private final static String NAME = "gendreauPostOpt";
|
||||||
|
|
||||||
|
private final RuinStrategy ruin;
|
||||||
|
|
||||||
|
private final VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
|
private final AbstractInsertionStrategy insertionStrategy;
|
||||||
|
|
||||||
|
private final RouteAlgorithm routeAlgorithm;
|
||||||
|
|
||||||
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
|
private Random random = RandomNumberGeneration.getRandom();
|
||||||
|
|
||||||
|
private int nOfIterations = 10;
|
||||||
|
|
||||||
|
private double shareOfJobsToRuin = 0.15;
|
||||||
|
|
||||||
|
public void setShareOfJobsToRuin(double shareOfJobsToRuin) {
|
||||||
|
this.shareOfJobsToRuin = shareOfJobsToRuin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GendreauPostOpt(VehicleRoutingProblem vrp, RuinStrategy ruin, AbstractInsertionStrategy insertionStrategy) {
|
||||||
|
super();
|
||||||
|
this.routeAlgorithm = insertionStrategy.getRouteAlgorithm();
|
||||||
|
this.ruin = ruin;
|
||||||
|
this.vrp = vrp;
|
||||||
|
this.insertionStrategy = insertionStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=gendreauPostOpt][iterations="+nOfIterations+"][share2ruin="+shareOfJobsToRuin+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRandom(Random random) {
|
||||||
|
this.random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setNuOfIterations(int nOfIterations) {
|
||||||
|
this.nOfIterations = nOfIterations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFleetManager(VehicleFleetManager vehicleFleetManager) {
|
||||||
|
this.fleetManager = vehicleFleetManager;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
|
||||||
|
// log.info("run gendreau postopt");
|
||||||
|
VehicleRoutingProblemSolution bestSolution = vrpSolution;
|
||||||
|
int itersWithoutImprovement = 0;
|
||||||
|
|
||||||
|
for(int i=0;i<nOfIterations;i++){
|
||||||
|
List<VehicleRoute> copiedRoutes = copyRoutes(bestSolution.getRoutes());
|
||||||
|
iniFleet(copiedRoutes);
|
||||||
|
|
||||||
|
VehicleRoute route2split = pickRouteThatHasAtLeastTwoJobs(copiedRoutes);
|
||||||
|
if(route2split == null) continue;
|
||||||
|
List<Job> jobsInRoute = getJobs(route2split);
|
||||||
|
Set<Job> unassignedJobs = new HashSet<Job>();
|
||||||
|
unassignedJobs.addAll(jobsInRoute);
|
||||||
|
copiedRoutes.remove(route2split);
|
||||||
|
|
||||||
|
Collections.shuffle(jobsInRoute,random);
|
||||||
|
Job targetJob = jobsInRoute.get(0);
|
||||||
|
int nOfJobs2BeRemovedAdditionally = (int) (shareOfJobsToRuin*(double)vrp.getJobs().size());
|
||||||
|
Collection<Job> unassignedJobsList = ruin.ruin(copiedRoutes, targetJob, nOfJobs2BeRemovedAdditionally);
|
||||||
|
unassignedJobs.addAll(unassignedJobsList);
|
||||||
|
|
||||||
|
VehicleRoute emptyRoute1 = VehicleRoute.emptyRoute();
|
||||||
|
copiedRoutes.add(emptyRoute1);
|
||||||
|
routeAlgorithm.insertJob(targetJob, routeAlgorithm.calculateBestInsertion(emptyRoute1, targetJob, Double.MAX_VALUE), emptyRoute1);
|
||||||
|
unassignedJobs.remove(targetJob);
|
||||||
|
|
||||||
|
VehicleRoute emptyRoute2 = VehicleRoute.emptyRoute();
|
||||||
|
copiedRoutes.add(emptyRoute2);
|
||||||
|
Job job2 = jobsInRoute.get(1);
|
||||||
|
routeAlgorithm.insertJob(job2, routeAlgorithm.calculateBestInsertion(emptyRoute2, job2, Double.MAX_VALUE), emptyRoute2);
|
||||||
|
unassignedJobs.remove(job2);
|
||||||
|
|
||||||
|
insertionStrategy.run(copiedRoutes, unassignedJobs, Double.MAX_VALUE);
|
||||||
|
double cost = getCost(copiedRoutes);
|
||||||
|
|
||||||
|
if(cost < bestSolution.getCost()){
|
||||||
|
// log.info("BING - new: " + cost + " old: " + bestSolution.getCost());
|
||||||
|
bestSolution = new VehicleRoutingProblemSolution(copiedRoutes, cost);
|
||||||
|
itersWithoutImprovement=0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
itersWithoutImprovement++;
|
||||||
|
if(itersWithoutImprovement > 200){
|
||||||
|
// log.info("BREAK i="+i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestSolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<VehicleRoute> copyRoutes(Collection<VehicleRoute> routes) {
|
||||||
|
List<VehicleRoute> routeList = new ArrayList<VehicleRoute>();
|
||||||
|
for(VehicleRoute r : routes){
|
||||||
|
routeList.add(VehicleRoute.copyOf(r));
|
||||||
|
}
|
||||||
|
return routeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void iniFleet(Collection<VehicleRoute> routes) {
|
||||||
|
fleetManager.unlockAll();
|
||||||
|
for(VehicleRoute route : routes){
|
||||||
|
if(!route.isEmpty()){
|
||||||
|
fleetManager.lock(route.getVehicle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getCost(Collection<VehicleRoute> routes) {
|
||||||
|
double c = 0.0;
|
||||||
|
for(VehicleRoute r : routes){
|
||||||
|
c+=r.getCost();
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Job> getJobs(VehicleRoute route2split) {
|
||||||
|
Set<Job> jobs = new HashSet<Job>();
|
||||||
|
for(TourActivity act : route2split.getTourActivities().getActivities()){
|
||||||
|
if(act instanceof JobActivity){
|
||||||
|
jobs.add(((JobActivity) act).getJob());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ArrayList<Job>(jobs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private VehicleRoute pickRouteThatHasAtLeastTwoJobs(Collection<VehicleRoute> routeList) {
|
||||||
|
List<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
||||||
|
for(VehicleRoute r : routeList){
|
||||||
|
if(getJobs(r).size() > 1){
|
||||||
|
routes.add(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(routes.isEmpty()) return null;
|
||||||
|
Collections.shuffle(routes,random);
|
||||||
|
return routes.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addModuleListener(SearchStrategyModuleListener moduleListener) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
115
jsprit-core/src/main/java/algorithms/InfiniteVehicles.java
Normal file
115
jsprit-core/src/main/java/algorithms/InfiniteVehicles.java
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleImpl.VehicleType;
|
||||||
|
|
||||||
|
class InfiniteVehicles implements VehicleFleetManager{
|
||||||
|
|
||||||
|
static class TypeKeyComparator implements Comparator<TypeKey>{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(TypeKey k1, TypeKey k2) {
|
||||||
|
double k1_fix = k1.type.getVehicleCostParams().fix;
|
||||||
|
double k2_fix = k2.type.getVehicleCostParams().fix;
|
||||||
|
return (int)(k1_fix - k2_fix);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(InfiniteVehicles.class);
|
||||||
|
|
||||||
|
private Map<TypeKey,Vehicle> types = new HashMap<TypeKey, Vehicle>();
|
||||||
|
|
||||||
|
private List<TypeKey> sortedTypes = new ArrayList<VehicleFleetManager.TypeKey>();
|
||||||
|
|
||||||
|
public InfiniteVehicles(Collection<Vehicle> vehicles){
|
||||||
|
extractTypes(vehicles);
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=infiniteVehicle]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void extractTypes(Collection<Vehicle> vehicles) {
|
||||||
|
for(Vehicle v : vehicles){
|
||||||
|
TypeKey typeKey = new TypeKey(v.getType(),v.getLocationId());
|
||||||
|
types.put(typeKey,v);
|
||||||
|
sortedTypes.add(typeKey);
|
||||||
|
|
||||||
|
}
|
||||||
|
Collections.sort(sortedTypes, new TypeKeyComparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vehicle getEmptyVehicle(TypeKey typeId) {
|
||||||
|
return types.get(typeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<TypeKey> getAvailableVehicleTypes() {
|
||||||
|
return sortedTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lock(Vehicle vehicle) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlock(Vehicle vehicle) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<TypeKey> getAvailableVehicleTypes(TypeKey withoutThisType) {
|
||||||
|
Set<TypeKey> typeSet = new HashSet<TypeKey>(types.keySet());
|
||||||
|
typeSet.remove(withoutThisType);
|
||||||
|
return typeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLocked(Vehicle vehicle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlockAll() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
interface InitialSolutionFactory {
|
||||||
|
|
||||||
|
public VehicleRoutingProblemSolution createInitialSolution(VehicleRoutingProblem vrp);
|
||||||
|
|
||||||
|
}
|
||||||
107
jsprit-core/src/main/java/algorithms/InsertionData.java
Normal file
107
jsprit-core/src/main/java/algorithms/InsertionData.java
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.Driver;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class InsertionData {
|
||||||
|
|
||||||
|
static class NoInsertionFound extends InsertionData{
|
||||||
|
|
||||||
|
public NoInsertionFound() {
|
||||||
|
super(Double.MAX_VALUE, NO_INDEX, NO_INDEX, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InsertionData noInsertion = new NoInsertionFound();
|
||||||
|
|
||||||
|
public static InsertionData noInsertionFound(){
|
||||||
|
return noInsertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int NO_INDEX = -1;
|
||||||
|
|
||||||
|
private final double insertionCost;
|
||||||
|
|
||||||
|
private final int pickupInsertionIndex;
|
||||||
|
|
||||||
|
private final int deliveryInsertionIndex;
|
||||||
|
|
||||||
|
private final Vehicle selectedVehicle;
|
||||||
|
|
||||||
|
private final Driver selectedDriver;
|
||||||
|
|
||||||
|
private double departureTime;
|
||||||
|
|
||||||
|
public InsertionData(double insertionCost, int pickupInsertionIndex, int deliveryInsertionIndex, Vehicle vehicle, Driver driver){
|
||||||
|
this.insertionCost = insertionCost;
|
||||||
|
this.pickupInsertionIndex = pickupInsertionIndex;
|
||||||
|
this.deliveryInsertionIndex = deliveryInsertionIndex;
|
||||||
|
this.selectedVehicle = vehicle;
|
||||||
|
this.selectedDriver = driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[iCost="+insertionCost+"][iIndex="+deliveryInsertionIndex+"][depTime="+departureTime+"][vehicle="+selectedVehicle+"][driver="+selectedDriver+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDeliveryInsertionIndex(){
|
||||||
|
return deliveryInsertionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPickupInsertionIndex(){
|
||||||
|
return pickupInsertionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getInsertionCost() {
|
||||||
|
return insertionCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vehicle getSelectedVehicle() {
|
||||||
|
return selectedVehicle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Driver getSelectedDriver(){
|
||||||
|
return selectedDriver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the departureTime
|
||||||
|
*/
|
||||||
|
public double getVehicleDepartureTime() {
|
||||||
|
return departureTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param departureTime the departureTime to set
|
||||||
|
*/
|
||||||
|
public void setVehicleDepartureTime(double departureTime) {
|
||||||
|
this.departureTime = departureTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
132
jsprit-core/src/main/java/algorithms/InsertionFactory.java
Normal file
132
jsprit-core/src/main/java/algorithms/InsertionFactory.java
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.configuration.HierarchicalConfiguration;
|
||||||
|
import org.apache.commons.configuration.XMLConfiguration;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblem.FleetComposition;
|
||||||
|
import basics.algo.InsertionListener;
|
||||||
|
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
||||||
|
|
||||||
|
class InsertionFactory {
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(InsertionFactory.class);
|
||||||
|
|
||||||
|
public static AbstractInsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config,
|
||||||
|
VehicleFleetManager vehicleFleetManager, RouteStates activityStates, List<PrioritizedVRAListener> algorithmListeners){
|
||||||
|
|
||||||
|
if(config.containsKey("[@name]")){
|
||||||
|
String insertionName = config.getString("[@name]");
|
||||||
|
if(!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion")){
|
||||||
|
new IllegalStateException(insertionName + " is not supported. use either \"bestInsertion\" or \"regretInsertion\"");
|
||||||
|
}
|
||||||
|
AbstractInsertionStrategy insertionStrategy = null;
|
||||||
|
List<InsertionListener> insertionListeners = new ArrayList<InsertionListener>();
|
||||||
|
List<PrioritizedVRAListener> algoListeners = new ArrayList<PrioritizedVRAListener>();
|
||||||
|
|
||||||
|
CalculatorBuilder calcBuilder = new CalculatorBuilder(insertionListeners, algorithmListeners);
|
||||||
|
calcBuilder.setActivityStates(activityStates);
|
||||||
|
calcBuilder.setVehicleRoutingProblem(vrp);
|
||||||
|
calcBuilder.setVehicleFleetManager(vehicleFleetManager);
|
||||||
|
|
||||||
|
if(config.containsKey("level")){
|
||||||
|
String level = config.getString("level");
|
||||||
|
if(level.equals("local")){
|
||||||
|
calcBuilder.setLocalLevel();
|
||||||
|
}
|
||||||
|
else if(level.equals("route")){
|
||||||
|
int forwardLooking = 0;
|
||||||
|
int memory = 1;
|
||||||
|
String forward = config.getString("level[@forwardLooking]");
|
||||||
|
String mem = config.getString("level[@memory]");
|
||||||
|
if(forward != null) forwardLooking = Integer.parseInt(forward);
|
||||||
|
else log.warn("parameter route[@forwardLooking] is missing. by default it is 0 which equals to local level");
|
||||||
|
if(mem != null) memory = Integer.parseInt(mem);
|
||||||
|
else log.warn("parameter route[@memory] is missing. by default it is 1");
|
||||||
|
calcBuilder.setRouteLevel(forwardLooking, memory);
|
||||||
|
}
|
||||||
|
else throw new IllegalStateException("level " + level + " is not known. currently it only knows \"local\" or \"route\"");
|
||||||
|
}
|
||||||
|
else calcBuilder.setLocalLevel();
|
||||||
|
|
||||||
|
if(config.containsKey("considerFixedCosts") || config.containsKey("considerFixedCost")){
|
||||||
|
String val = config.getString("considerFixedCosts");
|
||||||
|
if(val == null) val = config.getString("considerFixedCost");
|
||||||
|
if(val.equals("true")){
|
||||||
|
double fixedCostWeight = 0.5;
|
||||||
|
String weight = config.getString("considerFixedCosts[@weight]");
|
||||||
|
if(weight == null) weight = config.getString("considerFixedCost[@weight]");
|
||||||
|
if(weight != null) fixedCostWeight = Double.parseDouble(weight);
|
||||||
|
else log.warn("parameter considerFixedCosts[@weight] is missing. by default, it is 0.5.");
|
||||||
|
calcBuilder.considerFixedCosts(fixedCostWeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String timeSliceString = config.getString("experimental[@timeSlice]");
|
||||||
|
String neighbors = config.getString("experimental[@neighboringSlices]");
|
||||||
|
if(timeSliceString != null && neighbors != null){
|
||||||
|
calcBuilder.experimentalTimeScheduler(Double.parseDouble(timeSliceString),Integer.parseInt(neighbors));
|
||||||
|
}
|
||||||
|
|
||||||
|
JobInsertionCalculator jic = calcBuilder.build();
|
||||||
|
TourStateUpdater tourStateCalculator = new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts());
|
||||||
|
RouteAlgorithm routeAlgorithm = RouteAlgorithmImpl.newInstance(jic, tourStateCalculator);
|
||||||
|
routeAlgorithm.getListeners().add(new VehicleSwitched(vehicleFleetManager));
|
||||||
|
((RouteAlgorithmImpl) routeAlgorithm).setActivityStates(activityStates);
|
||||||
|
|
||||||
|
if(insertionName.equals("bestInsertion")){
|
||||||
|
insertionStrategy = BestInsertion.newInstance(routeAlgorithm);
|
||||||
|
}
|
||||||
|
else if(insertionName.equals("regretInsertion")){
|
||||||
|
insertionStrategy = RegretInsertion.newInstance(routeAlgorithm);
|
||||||
|
}
|
||||||
|
// else if(insertionName.equals("concurrentBestInsertion")){
|
||||||
|
// String processorsString = config.getString("[@processors]");
|
||||||
|
// int processors = 1;
|
||||||
|
// if(processorsString != null) processors = Integer.parseInt(processorsString);
|
||||||
|
//// BestInsertionConcurrent.newInstance(routeAlgorithm,)
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
insertionStrategy.addListener(new RemoveEmptyVehicles());
|
||||||
|
insertionStrategy.addListener(new ResetAndIniFleetManager(vehicleFleetManager));
|
||||||
|
insertionStrategy.addAllListener(insertionListeners);
|
||||||
|
// insertionStrategy.addListener(new FindCheaperVehicle(
|
||||||
|
// new FindCheaperVehicleAlgoNew(vehicleFleetManager, tourStateCalculator, auxCalculator)));
|
||||||
|
|
||||||
|
algorithmListeners.addAll(algoListeners);
|
||||||
|
|
||||||
|
return insertionStrategy;
|
||||||
|
}
|
||||||
|
else throw new IllegalStateException("cannot create insertionStrategy, since it has no name.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
66
jsprit-core/src/main/java/algorithms/InsertionStrategy.java
Normal file
66
jsprit-core/src/main/java/algorithms/InsertionStrategy.java
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface InsertionStrategy {
|
||||||
|
|
||||||
|
class Insertion {
|
||||||
|
|
||||||
|
private final VehicleRoute route;
|
||||||
|
|
||||||
|
private final InsertionData insertionData;
|
||||||
|
|
||||||
|
public Insertion(VehicleRoute vehicleRoute, InsertionData insertionData) {
|
||||||
|
super();
|
||||||
|
this.route = vehicleRoute;
|
||||||
|
this.insertionData = insertionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoute getRoute() {
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InsertionData getInsertionData() {
|
||||||
|
return insertionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns the unassigned jobs to service-providers
|
||||||
|
*
|
||||||
|
* @param vehicleRoutes
|
||||||
|
* @param unassignedJobs
|
||||||
|
* @param result2beat
|
||||||
|
*/
|
||||||
|
public void run(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs, double result2beat);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
|
||||||
|
interface InsertionStrategyFactory {
|
||||||
|
|
||||||
|
public InsertionStrategy createStrategy(VehicleRoutingProblem vrp);
|
||||||
|
|
||||||
|
}
|
||||||
23
jsprit-core/src/main/java/algorithms/JobDistance.java
Normal file
23
jsprit-core/src/main/java/algorithms/JobDistance.java
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
interface JobDistance {
|
||||||
|
|
||||||
|
public double calculateDistance(Job i, Job j);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class JobDistanceAvgCosts implements JobDistance {
|
||||||
|
|
||||||
|
private VehicleRoutingTransportCosts costs;
|
||||||
|
|
||||||
|
public JobDistanceAvgCosts(VehicleRoutingTransportCosts costs) {
|
||||||
|
super();
|
||||||
|
this.costs = costs;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double calculateDistance(Job i, Job j) {
|
||||||
|
double avgCost = 0.0;
|
||||||
|
// if (i instanceof Shipment && j instanceof Shipment) {
|
||||||
|
// if (i.equals(j)) {
|
||||||
|
// avgCost = 0.0;
|
||||||
|
// } else {
|
||||||
|
// Shipment s_i = (Shipment) i;
|
||||||
|
// Shipment s_j = (Shipment) j;
|
||||||
|
// double cost_i1_j1 = calcDist(s_i.getFromId(), s_j.getFromId());
|
||||||
|
// double cost_i1_j2 = calcDist(s_i.getFromId(), s_j.getToId());
|
||||||
|
// double cost_i2_j1 = calcDist(s_i.getToId(), s_j.getFromId());
|
||||||
|
// double cost_i2_j2 = calcDist(s_i.getToId(), s_j.getToId());
|
||||||
|
// avgCost = (cost_i1_j1 + cost_i1_j2 + cost_i2_j1 + cost_i2_j2) / 4;
|
||||||
|
// }
|
||||||
|
// } else
|
||||||
|
if (i instanceof Service && j instanceof Service) {
|
||||||
|
if (i.equals(j)) {
|
||||||
|
avgCost = 0.0;
|
||||||
|
} else {
|
||||||
|
Service s_i = (Service) i;
|
||||||
|
Service s_j = (Service) j;
|
||||||
|
avgCost = calcDist(s_i.getLocationId(), s_j.getLocationId());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"currently, this class just works with shipments and services.");
|
||||||
|
}
|
||||||
|
return avgCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double calcDist(String from, String to) {
|
||||||
|
return costs.getTransportCost(from, to, 0.0, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
66
jsprit-core/src/main/java/algorithms/JobDistanceBeeline.java
Normal file
66
jsprit-core/src/main/java/algorithms/JobDistanceBeeline.java
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import util.CrowFlyCosts;
|
||||||
|
import util.Locations;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Service;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class JobDistanceBeeline implements JobDistance {
|
||||||
|
|
||||||
|
private Locations locations;
|
||||||
|
|
||||||
|
public JobDistanceBeeline(Locations locations) {
|
||||||
|
super();
|
||||||
|
this.locations = locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double calculateDistance(Job i, Job j) {
|
||||||
|
double avgCost = 0.0;
|
||||||
|
// if (i instanceof Shipment && j instanceof Shipment) {
|
||||||
|
// if (i.equals(j)) {
|
||||||
|
// avgCost = 0.0;
|
||||||
|
// } else {
|
||||||
|
// Shipment s_i = (Shipment) i;
|
||||||
|
// Shipment s_j = (Shipment) j;
|
||||||
|
// double cost_i1_j1 = calcDist(s_i.getFromId(), s_j.getFromId());
|
||||||
|
// double cost_i1_j2 = calcDist(s_i.getFromId(), s_j.getToId());
|
||||||
|
// double cost_i2_j1 = calcDist(s_i.getToId(), s_j.getFromId());
|
||||||
|
// double cost_i2_j2 = calcDist(s_i.getToId(), s_j.getToId());
|
||||||
|
// avgCost = (cost_i1_j1 + cost_i1_j2 + cost_i2_j1 + cost_i2_j2) / 4;
|
||||||
|
// }
|
||||||
|
// } else
|
||||||
|
if (i instanceof Service && j instanceof Service) {
|
||||||
|
if (i.equals(j)) {
|
||||||
|
avgCost = 0.0;
|
||||||
|
} else {
|
||||||
|
Service s_i = (Service) i;
|
||||||
|
Service s_j = (Service) j;
|
||||||
|
avgCost = calcDist(s_i.getLocationId(), s_j.getLocationId());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"currently, this class just works with shipments and services.");
|
||||||
|
}
|
||||||
|
return avgCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double calcDist(String from, String to) {
|
||||||
|
return new CrowFlyCosts(locations).getTransportCost(from, to, 0.0,null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.Driver;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
interface JobInsertionCalculator {
|
||||||
|
|
||||||
|
public InsertionData calculate(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore);
|
||||||
|
|
||||||
|
}
|
||||||
156
jsprit-core/src/main/java/algorithms/JobObserver.java
Normal file
156
jsprit-core/src/main/java/algorithms/JobObserver.java
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import algorithms.RouteStates.ActivityState;
|
||||||
|
import basics.algo.AlgorithmEndsListener;
|
||||||
|
import basics.algo.JobInsertedListener;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
import basics.route.TourActivity.JobActivity;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
class JobObserver implements JobInsertedListener, BeforeJobInsertionListener, AlgorithmEndsListener{
|
||||||
|
|
||||||
|
private static class Info {
|
||||||
|
double depTime;
|
||||||
|
double tourSize;
|
||||||
|
double insertionIndex;
|
||||||
|
double error;
|
||||||
|
public Info(double depTime, double tourSize, double insertionIndex,
|
||||||
|
double error) {
|
||||||
|
super();
|
||||||
|
this.depTime = depTime;
|
||||||
|
this.tourSize = tourSize;
|
||||||
|
this.insertionIndex = insertionIndex;
|
||||||
|
this.error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String locationId = "70";
|
||||||
|
|
||||||
|
private double routeCostBefore;
|
||||||
|
private double estimatedMC;
|
||||||
|
private boolean beforeFirst = false;
|
||||||
|
|
||||||
|
private RouteStates actStates;
|
||||||
|
|
||||||
|
public void setActivityStates(RouteStates actStates){
|
||||||
|
this.actStates = actStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActivityState state(TourActivity act){
|
||||||
|
return actStates.getState(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Collection<Info> infos = new ArrayList<Info>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informJobInserted(int nOfJobsStill2Recreate, Job job2insert, VehicleRoute insertedIn) {
|
||||||
|
if(job2insert instanceof Service){
|
||||||
|
if(((Service) job2insert).getLocationId().equals(locationId)){
|
||||||
|
double actualMC = insertedIn.getCost()-routeCostBefore;
|
||||||
|
TourActivity act = getAct(job2insert,insertedIn);
|
||||||
|
double error = (estimatedMC-actualMC);
|
||||||
|
int tourSize = insertedIn.getTourActivities().getActivities().size();
|
||||||
|
int insertionIndex = getIndexOf(job2insert, insertedIn);
|
||||||
|
// infos.add(new Info())
|
||||||
|
double depTime = state(act).getEarliestOperationStart()+act.getOperationTime();
|
||||||
|
infos.add(new Info(depTime,tourSize,insertionIndex,error));
|
||||||
|
// System.out.println("[id=1][tourSize="+tourSize+"][index="+insertionIndex+
|
||||||
|
// "][earliestDeparture="+depTime+
|
||||||
|
// "][tourCostBefore="+routeCostBefore+"][routeCostAfter="+insertedIn.getCost()+"]" +
|
||||||
|
// "[estimated="+Math.round(estimatedMC)+"][actual="+Math.round(actualMC)+"][error(abs)="+error +
|
||||||
|
// "][errorPerNextCustomer="+ (error/(double)(tourSize-insertionIndex)) + "]");
|
||||||
|
routeCostBefore = 0.0;
|
||||||
|
estimatedMC = 0.0;
|
||||||
|
if(!beforeFirst) throw new IllegalStateException("ähhh");
|
||||||
|
beforeFirst = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TourActivity getAct(Job job2insert, VehicleRoute insertedIn) {
|
||||||
|
for(TourActivity act : insertedIn.getTourActivities().getActivities()){
|
||||||
|
if(act instanceof JobActivity){
|
||||||
|
if(((JobActivity) act).getJob().getId().equals(job2insert.getId())){
|
||||||
|
return act;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getIndexOf(Job job2insert, VehicleRoute insertedIn) {
|
||||||
|
int index=0;
|
||||||
|
for(TourActivity act : insertedIn.getTourActivities().getActivities()){
|
||||||
|
if(act instanceof JobActivity){
|
||||||
|
if(((JobActivity) act).getJob().getId().equals(job2insert.getId())){
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route) {
|
||||||
|
if(job instanceof Service){
|
||||||
|
if(((Service) job).getLocationId().equals(locationId)){
|
||||||
|
// System.out.println("[id=1][tourSize="+route.getTour().getActivities().size()+"][tourCost="+route.getCost()+"]" +
|
||||||
|
// "[estimatedMarginalInsertionCost="+data.getInsertionCost()+"]");
|
||||||
|
routeCostBefore = route.getCost();
|
||||||
|
estimatedMC = data.getInsertionCost();
|
||||||
|
beforeFirst = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
try {
|
||||||
|
BufferedWriter writer = new BufferedWriter(new FileWriter("output/errorAna.txt"));
|
||||||
|
for(Info info : infos){
|
||||||
|
writer.write(new StringBuilder().append(info.depTime).append(";").append(info.tourSize).append(";").append(info.insertionIndex).append(";")
|
||||||
|
.append(info.error).append("\n").toString());
|
||||||
|
}
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
36
jsprit-core/src/main/java/algorithms/JobRemover.java
Normal file
36
jsprit-core/src/main/java/algorithms/JobRemover.java
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
interface JobRemover {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes jobs from vehicRoute and return true if job has been successfully removed.
|
||||||
|
*
|
||||||
|
* @return true if job removed successfully, otherwise false
|
||||||
|
*/
|
||||||
|
public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
54
jsprit-core/src/main/java/algorithms/JobRemoverImpl.java
Normal file
54
jsprit-core/src/main/java/algorithms/JobRemoverImpl.java
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class JobRemoverImpl implements JobRemover{
|
||||||
|
|
||||||
|
interface RemoverListener {
|
||||||
|
public void informRemovedJob(Job j, VehicleRoute r);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<RemoverListener> remListeners = new ArrayList<RemoverListener>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute) {
|
||||||
|
boolean jobRemoved = vehicleRoute.getTourActivities().removeJob(job);
|
||||||
|
if(jobRemoved) informRemovedJob(job,vehicleRoute);
|
||||||
|
return jobRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void informRemovedJob(Job job, VehicleRoute vehicleRoute) {
|
||||||
|
for(RemoverListener l : remListeners) l.informRemovedJob(job, vehicleRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RemoverListener> getRemListeners() {
|
||||||
|
return remListeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.commons.math.stat.descriptive.moment.Mean;
|
||||||
|
import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.CrowFlyCosts;
|
||||||
|
import util.EuclideanDistanceCalculator;
|
||||||
|
import util.Locations;
|
||||||
|
import util.NeighborhoodImpl;
|
||||||
|
import util.Solutions;
|
||||||
|
import algorithms.selectors.SelectBest;
|
||||||
|
import basics.VehicleRoutingAlgorithm;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.AlgorithmStartsListener;
|
||||||
|
import basics.algo.VehicleRoutingAlgorithmFactory;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
public class NeighborhoodThresholdInitialiser implements AlgorithmStartsListener{
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(NeighborhoodThresholdInitialiser.class);
|
||||||
|
|
||||||
|
private NeighborhoodImpl neighborhood;
|
||||||
|
|
||||||
|
private VehicleRoutingAlgorithmFactory routingAlgorithmFactory = new VehicleRoutingAlgorithmFactory() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp) {
|
||||||
|
VehicleRoutingAlgorithm algorithm = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "resources/config.xml");
|
||||||
|
return algorithm;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private int crowFlySpeed = 20;
|
||||||
|
|
||||||
|
public NeighborhoodThresholdInitialiser(NeighborhoodImpl neighborhood) {
|
||||||
|
this.neighborhood = neighborhood;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param crowFlySpeed the crowFlySpeed to set
|
||||||
|
*/
|
||||||
|
public void setCrowFlySpeed(int crowFlySpeed) {
|
||||||
|
this.crowFlySpeed = crowFlySpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param routingAlgorithmFactory the routingAlgorithm to set
|
||||||
|
*/
|
||||||
|
public void setRoutingAlgorithmFactory(VehicleRoutingAlgorithmFactory routingAlgorithmFactory) {
|
||||||
|
this.routingAlgorithmFactory = routingAlgorithmFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialise(VehicleRoutingProblem problem){
|
||||||
|
informAlgorithmStarts(problem, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
|
||||||
|
builder.addAllJobs(problem.getJobs().values());
|
||||||
|
builder.addAllVehicles(problem.getVehicles());
|
||||||
|
VehicleRoutingProblem pblm = builder.build();
|
||||||
|
CrowFlyCosts crowFly = new CrowFlyCosts(builder.getLocations());
|
||||||
|
crowFly.speed = crowFlySpeed;
|
||||||
|
pblm.setTransportCosts(crowFly);
|
||||||
|
|
||||||
|
VehicleRoutingAlgorithm algo = routingAlgorithmFactory.createAlgorithm(pblm);
|
||||||
|
Collection<VehicleRoutingProblemSolution> mySolutions = algo.searchSolutions();
|
||||||
|
|
||||||
|
double threshold = determineThreshold(pblm,builder.getLocations(), mySolutions);
|
||||||
|
neighborhood.setThreshold(threshold);
|
||||||
|
neighborhood.initialise();
|
||||||
|
}
|
||||||
|
|
||||||
|
private double determineThreshold(VehicleRoutingProblem pblm, Locations locations, Collection<VehicleRoutingProblemSolution> mySolutions) {
|
||||||
|
VehicleRoutingProblemSolution bestSolution = Solutions.getBest(mySolutions);
|
||||||
|
double[] distances = new double[bestSolution.getRoutes().size()+pblm.getJobs().size()];
|
||||||
|
getDistances(distances,bestSolution,locations);
|
||||||
|
Mean mean = new Mean();
|
||||||
|
double meanValue = mean.evaluate(distances);
|
||||||
|
StandardDeviation dev = new StandardDeviation();
|
||||||
|
double devValue = dev.evaluate(distances, meanValue);
|
||||||
|
log.info("mean="+meanValue+", dev="+devValue);
|
||||||
|
return meanValue + devValue;
|
||||||
|
// + 2*devValue;
|
||||||
|
// return Double.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getDistances(double[] distances, VehicleRoutingProblemSolution bestSolution, Locations locations) {
|
||||||
|
int index = 0;
|
||||||
|
for(VehicleRoute route : bestSolution.getRoutes()){
|
||||||
|
TourActivity prev = null;
|
||||||
|
for(TourActivity act : route.getTourActivities().getActivities()){
|
||||||
|
if(prev == null){ prev = act; continue; }
|
||||||
|
double dist = EuclideanDistanceCalculator.calculateDistance(locations.getCoord(prev.getLocationId()), locations.getCoord(act.getLocationId()));
|
||||||
|
// log.info("dist="+dist);
|
||||||
|
distances[index] = dist;
|
||||||
|
index++;
|
||||||
|
prev = act;
|
||||||
|
}
|
||||||
|
// double dist = EuclideanDistanceCalculator.calculateDistance(locations.getCoord(prev.getLocationId()), locations.getCoord(route.getEnd().getLocationId()));
|
||||||
|
// distances[index] = dist;
|
||||||
|
// index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
229
jsprit-core/src/main/java/algorithms/ParRegretInsertion.java
Normal file
229
jsprit-core/src/main/java/algorithms/ParRegretInsertion.java
Normal file
|
|
@ -0,0 +1,229 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
///*******************************************************************************
|
||||||
|
// * Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
// * eMail: stefan.schroeder@kit.edu
|
||||||
|
// *
|
||||||
|
// * All rights reserved. This program and the accompanying materials
|
||||||
|
// * are made available under the terms of the GNU Public License v2.0
|
||||||
|
// * which accompanies this distribution, and is available at
|
||||||
|
// * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
// *
|
||||||
|
// * Contributors:
|
||||||
|
// * Stefan Schroeder - initial API and implementation
|
||||||
|
// ******************************************************************************/
|
||||||
|
//package algorithms;
|
||||||
|
//
|
||||||
|
//import java.util.ArrayList;
|
||||||
|
//import java.util.Collection;
|
||||||
|
//import java.util.List;
|
||||||
|
//import java.util.concurrent.Callable;
|
||||||
|
//import java.util.concurrent.CompletionService;
|
||||||
|
//import java.util.concurrent.ExecutionException;
|
||||||
|
//import java.util.concurrent.ExecutorCompletionService;
|
||||||
|
//import java.util.concurrent.ExecutorService;
|
||||||
|
//import java.util.concurrent.Future;
|
||||||
|
//
|
||||||
|
//import org.apache.log4j.Logger;
|
||||||
|
//
|
||||||
|
//import basics.InsertionData;
|
||||||
|
//import basics.Job;
|
||||||
|
//import basics.Service;
|
||||||
|
//import basics.Shipment;
|
||||||
|
//import basics.VehicleRoute;
|
||||||
|
//import basics.InsertionData.NoInsertionFound;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * Simplest recreation strategy. All removed customers are inserted where insertion costs are minimal. I.e. each tour-agent is asked for
|
||||||
|
// * minimal marginal insertion costs. The tour-agent offering the lowest marginal insertion costs gets the customer/shipment.
|
||||||
|
// *
|
||||||
|
// * @author stefan schroeder
|
||||||
|
// *
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//final class ParRegretInsertion extends AbstractRecreationStrategy{
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// private Logger logger = Logger.getLogger(ParRegretInsertion.class);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// public static double scoreParam_of_timeWindowLegth = 0.0;
|
||||||
|
//
|
||||||
|
// private ExecutorService executor;
|
||||||
|
//
|
||||||
|
// public static double scoreParam_of_distance = 0.5;
|
||||||
|
//
|
||||||
|
// private DepotDistance depotDistance;
|
||||||
|
//
|
||||||
|
// private RouteAlgorithm routeAlgorithm;
|
||||||
|
//
|
||||||
|
// private VehicleRouteFactory vehicleRouteFactory;
|
||||||
|
//
|
||||||
|
// public ParRegretInsertion(ExecutorService executor, RouteAlgorithm routeAlgorithm, VehicleRouteFactory routeFactory, DepotDistance depotDistance) {
|
||||||
|
// super();
|
||||||
|
// this.executor = executor;
|
||||||
|
// this.routeAlgorithm = routeAlgorithm;
|
||||||
|
// this.depotDistance = depotDistance;
|
||||||
|
// this.vehicleRouteFactory = routeFactory;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void recreate(final Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs, double result2beat) {
|
||||||
|
// List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||||
|
// informRecreationStart(unassignedJobs.size());
|
||||||
|
//
|
||||||
|
// while(!jobs.isEmpty()){
|
||||||
|
// List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||||
|
// ScoredJob bestScoredJob = null;
|
||||||
|
// double bestScore = -1*Double.MAX_VALUE;
|
||||||
|
// CompletionService<ScoredJob> completionService = new ExecutorCompletionService<ScoredJob>(executor);
|
||||||
|
//
|
||||||
|
// for(final Job unassignedJob : unassignedJobList){
|
||||||
|
// completionService.submit(new Callable<ScoredJob>(){
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public ScoredJob call() throws Exception {
|
||||||
|
// return getScoredJob(vehicleRoutes, unassignedJob);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// try{
|
||||||
|
// for(int i=0;i<unassignedJobList.size();i++){
|
||||||
|
// Future<ScoredJob> fsj = completionService.take();
|
||||||
|
// ScoredJob scoredJob = fsj.get();
|
||||||
|
// if(scoredJob == null){
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// if(scoredJob.getScore() > bestScore){
|
||||||
|
// bestScoredJob = scoredJob;
|
||||||
|
// bestScore = scoredJob.getScore();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// catch(InterruptedException e){
|
||||||
|
// Thread.currentThread().interrupt();
|
||||||
|
// }
|
||||||
|
// catch (ExecutionException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// logger.error(e.getCause().toString());
|
||||||
|
// System.exit(1);
|
||||||
|
// }
|
||||||
|
// if(bestScoredJob == null){
|
||||||
|
// Job job = unassignedJobList.get(0);
|
||||||
|
// VehicleRoute newRoute = vehicleRouteFactory.createVehicleRoute();
|
||||||
|
// InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, job, Double.MAX_VALUE);
|
||||||
|
// if(bestI instanceof InsertionData.NoInsertionFound) throw new IllegalStateException("given the vehicles, could not create a valid solution");
|
||||||
|
// routeAlgorithm.insertJob(job,bestI,newRoute);
|
||||||
|
// vehicleRoutes.add(newRoute);
|
||||||
|
// jobs.remove(job);
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// else{
|
||||||
|
// routeAlgorithm.insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(),bestScoredJob.getRoute());
|
||||||
|
// jobs.remove(bestScoredJob.getJob());
|
||||||
|
// }
|
||||||
|
// informJobInsertion(null, (unassignedJobList.size()-1), null);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private ScoredJob getScoredJob(Collection<VehicleRoute> vehicleRoutes, Job job){
|
||||||
|
// InsertionData best = null;
|
||||||
|
// InsertionData secondBest = null;
|
||||||
|
// VehicleRoute bestRoute = null;
|
||||||
|
// double benchmark = Double.MAX_VALUE;
|
||||||
|
// for(VehicleRoute route : vehicleRoutes){
|
||||||
|
// if(secondBest != null){
|
||||||
|
// benchmark = secondBest.getInsertionCost();
|
||||||
|
// }
|
||||||
|
// InsertionData iData = routeAlgorithm.calculateBestInsertion(route, job, benchmark);
|
||||||
|
// if(iData instanceof NoInsertionFound) continue;
|
||||||
|
// if(best == null) {
|
||||||
|
// best = iData;
|
||||||
|
// bestRoute = route;
|
||||||
|
// }
|
||||||
|
// else if(iData.getInsertionCost() < best.getInsertionCost()){
|
||||||
|
// secondBest = best;
|
||||||
|
// best = iData;
|
||||||
|
// bestRoute = route;
|
||||||
|
// }
|
||||||
|
// else if(secondBest == null) secondBest = iData;
|
||||||
|
// else if(iData.getInsertionCost() < secondBest.getInsertionCost()) secondBest = iData;
|
||||||
|
// }
|
||||||
|
// if(best == null){
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// double score = score(job,best,secondBest);
|
||||||
|
// return new ScoredJob(job, score, best, bestRoute);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private double score(Job unassignedJob, InsertionData best, InsertionData secondBest) {
|
||||||
|
// /*
|
||||||
|
// * wieder so eine bescheuerte fallunterscheidung. hier will ich
|
||||||
|
// * doch einfach nur das maßgebende zeitfenster des jobs
|
||||||
|
// * job.getTimeWindow()
|
||||||
|
// * Problem: eine Shipment hat zwei TWs, sowohl ein PickupTW als auch
|
||||||
|
// * ein DeliveryTW
|
||||||
|
// */
|
||||||
|
// double twStart = 0.0;
|
||||||
|
// double twEnd = 0.0;
|
||||||
|
// if(unassignedJob instanceof Shipment){
|
||||||
|
// twStart = ((Shipment) unassignedJob).getDeliveryTW().getStart();
|
||||||
|
// twEnd = ((Shipment) unassignedJob).getDeliveryTW().getEnd();
|
||||||
|
// }
|
||||||
|
// else if(unassignedJob instanceof Service){
|
||||||
|
// twStart = ((Service) unassignedJob).getTimeWindow().getStart();
|
||||||
|
// twEnd = ((Service) unassignedJob).getTimeWindow().getEnd();
|
||||||
|
// }
|
||||||
|
// if(best == null){
|
||||||
|
// throw new IllegalStateException("cannot insert job " + unassignedJob.getId());
|
||||||
|
// }
|
||||||
|
// if(secondBest == null){
|
||||||
|
// return Double.MAX_VALUE;
|
||||||
|
// }
|
||||||
|
//// double score = (secondBest.getInsertionCost()-best.getInsertionCost()) + scoreParam_of_distance*getDistance(unassignedJob) - scoreParam_of_timeWindowLegth*(twEnd-twStart);
|
||||||
|
//// logger.info("priceDiff="+ (secondBest.getPrice()-best.getPrice()) + "; param*dist="
|
||||||
|
// double timeWindowInfluence = scoreParam_of_timeWindowLegth*(twEnd-twStart);
|
||||||
|
// double distanceInfluence = scoreParam_of_distance*getDistance(unassignedJob);
|
||||||
|
// double score = (secondBest.getInsertionCost()-best.getInsertionCost()) - timeWindowInfluence
|
||||||
|
// + distanceInfluence;
|
||||||
|
// return score;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private double getDistance(Job unassignedJob) {
|
||||||
|
// return depotDistance.calcDistance(unassignedJob);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// public double getTimeParam() {
|
||||||
|
// return scoreParam_of_timeWindowLegth;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
210
jsprit-core/src/main/java/algorithms/RegretInsertion.java
Normal file
210
jsprit-core/src/main/java/algorithms/RegretInsertion.java
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import algorithms.InsertionData.NoInsertionFound;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insertion based an regret approach.
|
||||||
|
*
|
||||||
|
* <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference
|
||||||
|
* between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction.
|
||||||
|
* The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this
|
||||||
|
* customer immediatedly. If difference is not that high, it might not impact solution if this customer is inserted later.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
final class RegretInsertion extends AbstractInsertionStrategy{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scorer to include other impacts on score such as time-window length or distance to depot.
|
||||||
|
*
|
||||||
|
* @author schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static interface ScoringFunction {
|
||||||
|
|
||||||
|
public double score(Job job);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scorer that includes the length of the time-window when scoring a job. The wider the time-window, the lower the score.
|
||||||
|
*
|
||||||
|
* <p>This is the default scorer, i.e.: score = (secondBest - firstBest) + this.TimeWindowScorer.score(job)
|
||||||
|
*
|
||||||
|
* @author schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static class TimeWindowScorer implements ScoringFunction {
|
||||||
|
|
||||||
|
private double tw_scoringParam = - 0.1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double score(Job job) {
|
||||||
|
double twStart = 0.0;
|
||||||
|
double twEnd = 0.0;
|
||||||
|
// if(job instanceof Shipment){
|
||||||
|
// twStart = ((Shipment) job).getDeliveryTW().getStart();
|
||||||
|
// twEnd = ((Shipment) job).getDeliveryTW().getEnd();
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
if(job instanceof Service){
|
||||||
|
twStart = ((Service) job).getTimeWindow().getStart();
|
||||||
|
twEnd = ((Service) job).getTimeWindow().getEnd();
|
||||||
|
}
|
||||||
|
return (twEnd-twStart)*tw_scoringParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=timeWindowScorer][scoringParam="+tw_scoringParam+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RegretInsertion newInstance(RouteAlgorithm routeAlgorithm) {
|
||||||
|
return new RegretInsertion(routeAlgorithm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Logger logger = Logger.getLogger(RegretInsertion.class);
|
||||||
|
|
||||||
|
private RouteAlgorithm routeAlgorithm;
|
||||||
|
|
||||||
|
private ScoringFunction scoringFunction = new TimeWindowScorer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scoring function.
|
||||||
|
*
|
||||||
|
* <p>By default, the this.TimeWindowScorer is used.
|
||||||
|
*
|
||||||
|
* @param scoringFunction
|
||||||
|
*/
|
||||||
|
public void setScoringFunction(ScoringFunction scoringFunction) {
|
||||||
|
this.scoringFunction = scoringFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegretInsertion(RouteAlgorithm routeAlgorithm) {
|
||||||
|
super();
|
||||||
|
this.routeAlgorithm = routeAlgorithm;
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=regretInsertion][additionalScorer="+scoringFunction+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteAlgorithm getRouteAlgorithm(){
|
||||||
|
return routeAlgorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs insertion.
|
||||||
|
*
|
||||||
|
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs, double resultToBeat) {
|
||||||
|
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||||
|
informInsertionStarts(routes,unassignedJobs.size());
|
||||||
|
int inserted = 0;
|
||||||
|
while(!jobs.isEmpty()){
|
||||||
|
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||||
|
ScoredJob bestScoredJob = null;
|
||||||
|
double bestScore = -1*Double.MAX_VALUE;
|
||||||
|
VehicleRoute insertIn = null;
|
||||||
|
|
||||||
|
for(Job unassignedJob : unassignedJobList){
|
||||||
|
InsertionData best = null;
|
||||||
|
InsertionData secondBest = null;
|
||||||
|
VehicleRoute bestRoute = null;
|
||||||
|
|
||||||
|
double benchmark = Double.MAX_VALUE;
|
||||||
|
for(VehicleRoute route : routes){
|
||||||
|
if(secondBest != null){
|
||||||
|
benchmark = secondBest.getInsertionCost();
|
||||||
|
}
|
||||||
|
InsertionData iData = routeAlgorithm.calculateBestInsertion(route, unassignedJob, benchmark);
|
||||||
|
if(iData instanceof NoInsertionFound) continue;
|
||||||
|
if(best == null){
|
||||||
|
best = iData;
|
||||||
|
bestRoute = route;
|
||||||
|
}
|
||||||
|
else if(iData.getInsertionCost() < best.getInsertionCost()){
|
||||||
|
secondBest = best;
|
||||||
|
best = iData;
|
||||||
|
bestRoute = route;
|
||||||
|
}
|
||||||
|
else if(secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())){
|
||||||
|
secondBest = iData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(best == null){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
double score = score(unassignedJob,best,secondBest);
|
||||||
|
if(score > bestScore){
|
||||||
|
bestScoredJob = new ScoredJob(unassignedJob,score,best,bestRoute);
|
||||||
|
bestScore = score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Job assignedJob;
|
||||||
|
if(bestScoredJob == null){
|
||||||
|
Job job = unassignedJobList.get(0);
|
||||||
|
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
||||||
|
InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, job, Double.MAX_VALUE);
|
||||||
|
if(bestI instanceof InsertionData.NoInsertionFound) throw new IllegalStateException("given the vehicles, could not create a valid solution");
|
||||||
|
insertIn=newRoute;
|
||||||
|
assignedJob=job;
|
||||||
|
routeAlgorithm.insertJob(job,bestI,newRoute);
|
||||||
|
routes.add(newRoute);
|
||||||
|
jobs.remove(job);
|
||||||
|
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
routeAlgorithm.insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||||
|
insertIn=bestScoredJob.getRoute();
|
||||||
|
assignedJob=bestScoredJob.getJob();
|
||||||
|
jobs.remove(bestScoredJob.getJob());
|
||||||
|
}
|
||||||
|
inserted++;
|
||||||
|
informJobInserted((unassignedJobList.size()-inserted), assignedJob, insertIn);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double score(Job unassignedJob, InsertionData best, InsertionData secondBest) {
|
||||||
|
if(best == null){
|
||||||
|
throw new IllegalStateException("cannot insert job " + unassignedJob.getId());
|
||||||
|
}
|
||||||
|
if(secondBest == null){
|
||||||
|
return Double.MAX_VALUE;
|
||||||
|
}
|
||||||
|
return (secondBest.getInsertionCost()-best.getInsertionCost()) + scoringFunction.score(unassignedJob);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
import basics.algo.InsertionEndsListener;
|
||||||
|
import basics.algo.InsertionStartsListener;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class RemoveEmptyVehicles implements InsertionStartsListener, InsertionEndsListener{
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(RemoveEmptyVehicles.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2Recreate) {
|
||||||
|
// List<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
|
||||||
|
// for(VehicleRoute route : routes){
|
||||||
|
// if(route.isEmpty()) { vehicleRoutes.remove(route); }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=removeEmptyVehicles]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
|
List<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
|
||||||
|
for(VehicleRoute route : routes){
|
||||||
|
if(route.isEmpty()) { vehicleRoutes.remove(route); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.algo.InsertionStartsListener;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class ResetAndIniFleetManager implements InsertionStartsListener{
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(ResetAndIniFleetManager.class);
|
||||||
|
|
||||||
|
private VehicleFleetManager vehicleFleetManager;
|
||||||
|
|
||||||
|
ResetAndIniFleetManager(VehicleFleetManager vehicleFleetManager) {
|
||||||
|
super();
|
||||||
|
this.vehicleFleetManager = vehicleFleetManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2Recreate) {
|
||||||
|
vehicleFleetManager.unlockAll();
|
||||||
|
for(VehicleRoute route : vehicleRoutes){
|
||||||
|
if(!route.isEmpty()){
|
||||||
|
vehicleFleetManager.lock(route.getVehicle());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// log.info("#lockedVehicles=" + ((VehicleFleetManagerImpl)vehicleFleetManager).sizeOfLockedVehicles() + " #routes="+vehicleRoutes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=resetAndIniFleetManager]";
|
||||||
|
}
|
||||||
|
}
|
||||||
92
jsprit-core/src/main/java/algorithms/RouteAlgorithm.java
Normal file
92
jsprit-core/src/main/java/algorithms/RouteAlgorithm.java
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
interface RouteAlgorithm {
|
||||||
|
|
||||||
|
interface RouteAlgorithmListener {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface JobRemovedListener extends RouteAlgorithmListener{
|
||||||
|
public void removed(VehicleRoute route, Job job);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface JobInsertedListener extends RouteAlgorithmListener{
|
||||||
|
public void inserted(VehicleRoute route, Job job);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VehicleSwitchedListener extends RouteAlgorithmListener{
|
||||||
|
public void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the best insertion position and the corresponding marginal costs of inserting the job (according to the insertionCostCalculator).
|
||||||
|
* This does not affect any input parameter, thus the vehicleRoute and its data will not be changed/affected.
|
||||||
|
*
|
||||||
|
* @param VehicleRoute, Job, double
|
||||||
|
* @return InsertionData
|
||||||
|
*/
|
||||||
|
public InsertionData calculateBestInsertion(VehicleRoute vehicleRoute, Job job, double bestKnownPrice);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes job from vehicleRoute and does not update the resulting tour. Thus the tour state might not be valid anymore.
|
||||||
|
* Note that this changes vehicleRoute!
|
||||||
|
*
|
||||||
|
* @return true if job removed successfully, otherwise false
|
||||||
|
*/
|
||||||
|
public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes job from input parameter vehicleRoute AND updates the state of the resulting tour with tourStateCalc.
|
||||||
|
* Note that this changes para vehicleRoute!
|
||||||
|
*/
|
||||||
|
public boolean removeJob(Job job, VehicleRoute vehicleRoute);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts job into vehicleRoute.getTour().
|
||||||
|
* Please note, that this changes the parameter vehicleRoute!
|
||||||
|
*/
|
||||||
|
public void insertJobWithoutTourUpdate(VehicleRoute vehicleRoute, Job job, InsertionData insertionData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts job into vehicleRoute.getTour().
|
||||||
|
* Please note, that this changes the parameter vehicleRoute!
|
||||||
|
*/
|
||||||
|
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates vehicleRoute, i.e. uses the tourStateCalculator to update for example timeWindows and loads on vehicleRoute.getTour()
|
||||||
|
* Note that this changes the parameter vehicleRoute!
|
||||||
|
*/
|
||||||
|
public void updateTour(VehicleRoute vehicleRoute);
|
||||||
|
|
||||||
|
public Collection<RouteAlgorithmListener> getListeners();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
181
jsprit-core/src/main/java/algorithms/RouteAlgorithmImpl.java
Normal file
181
jsprit-core/src/main/java/algorithms/RouteAlgorithmImpl.java
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import algorithms.RouteStates.ActivityState;
|
||||||
|
import algorithms.InsertionData.NoInsertionFound;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.route.ServiceActivity;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class RouteAlgorithmImpl implements RouteAlgorithm {
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(RouteAlgorithmImpl.class);
|
||||||
|
|
||||||
|
static double NO_DEPARTURE_TIME = -12345.12345;
|
||||||
|
|
||||||
|
private String algoDescription = "algorithm to remove and insert jobs from vehicleRoutes. it also calculates marginal costs of the best insertion of a " +
|
||||||
|
"job into the given vehicle route";
|
||||||
|
|
||||||
|
public static RouteAlgorithmImpl newInstance(JobInsertionCalculator jobInsertionCalculator, VehicleRouteUpdater tourStateCalculator){
|
||||||
|
return new RouteAlgorithmImpl(jobInsertionCalculator, tourStateCalculator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<RouteAlgorithmListener> listeners = new ArrayList<RouteAlgorithmListener>();
|
||||||
|
|
||||||
|
private VehicleRouteUpdater tourCalculator;
|
||||||
|
|
||||||
|
private JobInsertionCalculator insertionCostCalculator;
|
||||||
|
|
||||||
|
private RouteStates actStates;
|
||||||
|
|
||||||
|
public void setActivityStates(RouteStates actStates){
|
||||||
|
this.actStates = actStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActivityState state(TourActivity act){
|
||||||
|
return actStates.getState(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RouteAlgorithmImpl(JobInsertionCalculator insertionCostCalculator, VehicleRouteUpdater tourCalculator){
|
||||||
|
this.tourCalculator = tourCalculator;
|
||||||
|
this.insertionCostCalculator = insertionCostCalculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public InsertionData calculateBestInsertion(VehicleRoute vehicleRoute, Job job, double bestKnownCost) {
|
||||||
|
return insertionCostCalculator.calculate(vehicleRoute, job, null, NO_DEPARTURE_TIME, null, bestKnownCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute) {
|
||||||
|
boolean removed = vehicleRoute.getTourActivities().removeJob(job);
|
||||||
|
if(removed){
|
||||||
|
jobRemoved(vehicleRoute,job);
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void jobRemoved(VehicleRoute vehicleRoute, Job job) {
|
||||||
|
for(RouteAlgorithmListener l : listeners){
|
||||||
|
if(l instanceof JobRemovedListener){
|
||||||
|
((JobRemovedListener) l).removed(vehicleRoute, job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean removeJob(Job job, VehicleRoute vehicleRoute){
|
||||||
|
boolean removed = removeJobWithoutTourUpdate(job, vehicleRoute);
|
||||||
|
if(removed) updateTour(vehicleRoute);
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void updateTour(VehicleRoute vehicleRoute){
|
||||||
|
boolean tourIsFeasible = tourCalculator.updateRoute(vehicleRoute);
|
||||||
|
if(!tourIsFeasible){
|
||||||
|
throw new IllegalStateException("At this point tour should be feasible. but it is not. \n currentTour=" + vehicleRoute.getTourActivities() +
|
||||||
|
"\n error sources: check jobInsertionCostCalculators and actInsertionCalculators. somehow an insertion is made, althought a hard constraint is broken. Here, hard constraints refer to \n" +
|
||||||
|
"hard time-window constraints. If you want to deal with such constraints, make sure a violation is penalized properly (such that it can never be the best insertion position). \n" +
|
||||||
|
"If you use CalculatesServiceInsertion and CalculatesActivityInsertion, the only hard constraint is the vehicle-capacity constraints. A violation of time-windows must be penalized in \n" +
|
||||||
|
"the vehicleRouteCostFunction. For example: in handleActivity(....) one can check whether the act start-time is higher than the latestOperationStartTime. If so penalize it with a very high value. \n" +
|
||||||
|
"For example: \n" +
|
||||||
|
"public void handleActivity(TourActivity tourAct, double startTime, double endTime) {\n" +
|
||||||
|
"\tif(startTime > tourAct.getLatestOperationStartTime()){\n" +
|
||||||
|
"\t\tcost += Double.MAX_VALUE;\n" +
|
||||||
|
"\t}\n" +
|
||||||
|
"});");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void insertJobWithoutTourUpdate(VehicleRoute vehicleRoute, Job job, InsertionData insertionData) {
|
||||||
|
if(insertionData == null || (insertionData instanceof NoInsertionFound)) throw new IllegalStateException("insertionData null. cannot insert job.");
|
||||||
|
if(job == null) throw new IllegalStateException("cannot insert null-job");
|
||||||
|
if(!(vehicleRoute.getVehicle().getId().toString().equals(insertionData.getSelectedVehicle().getId().toString()))){
|
||||||
|
vehicleSwitched(vehicleRoute.getVehicle(),insertionData.getSelectedVehicle());
|
||||||
|
vehicleRoute.setVehicle(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
|
||||||
|
}
|
||||||
|
if(job instanceof Service) {
|
||||||
|
vehicleRoute.getTourActivities().addActivity(insertionData.getDeliveryInsertionIndex(), ServiceActivity.newInstance((Service)job));
|
||||||
|
// if(vehicleRoute.getStart().getEndTime() != insertionData.getVehicleDepartureTime()){
|
||||||
|
// logger.info("depTime switched from " + vehicleRoute.getStart().getEndTime() + " to " + insertionData.getVehicleDepartureTime());
|
||||||
|
// }
|
||||||
|
vehicleRoute.setDepartureTime(insertionData.getVehicleDepartureTime());
|
||||||
|
}
|
||||||
|
else throw new IllegalStateException("neither service nor shipment. this is not supported.");
|
||||||
|
jobInserted(vehicleRoute,job);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle) {
|
||||||
|
for(RouteAlgorithmListener l : listeners){
|
||||||
|
if(l instanceof VehicleSwitchedListener){
|
||||||
|
((VehicleSwitchedListener) l).vehicleSwitched(oldVehicle,newVehicle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void jobInserted(VehicleRoute vehicleRoute, Job job) {
|
||||||
|
for(RouteAlgorithmListener l : listeners){
|
||||||
|
if(l instanceof JobInsertedListener){
|
||||||
|
((JobInsertedListener) l).inserted(vehicleRoute, job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute){
|
||||||
|
insertJobWithoutTourUpdate(vehicleRoute, job, insertionData);
|
||||||
|
updateTour(vehicleRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return algoDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertJob(Service service, int serviceInsertionIndex, VehicleRoute vehicleRoute) {
|
||||||
|
// TourActivity del = actStates.getActivity(service,true);
|
||||||
|
vehicleRoute.getTourActivities().addActivity(serviceInsertionIndex, ServiceActivity.newInstance(service));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Collection<RouteAlgorithmListener> getListeners() {
|
||||||
|
return listeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlgoDescription(String algoDescription) {
|
||||||
|
this.algoDescription = algoDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
208
jsprit-core/src/main/java/algorithms/RouteStates.java
Normal file
208
jsprit-core/src/main/java/algorithms/RouteStates.java
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.AlgorithmEndsListener;
|
||||||
|
import basics.algo.IterationEndsListener;
|
||||||
|
import basics.algo.IterationStartsListener;
|
||||||
|
import basics.route.ServiceActivity;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class RouteStates implements IterationStartsListener{
|
||||||
|
|
||||||
|
Logger log = Logger.getLogger(RouteStates.class);
|
||||||
|
|
||||||
|
static class RouteState {
|
||||||
|
private double costs;
|
||||||
|
private int load;
|
||||||
|
private VehicleRoute route;
|
||||||
|
public RouteState(VehicleRoute route) {
|
||||||
|
super();
|
||||||
|
this.route = route;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the costs
|
||||||
|
*/
|
||||||
|
public double getCosts() {
|
||||||
|
return costs;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param costs the costs to set
|
||||||
|
*/
|
||||||
|
public void setCosts(double costs) {
|
||||||
|
this.costs = costs;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the load
|
||||||
|
*/
|
||||||
|
public int getLoad() {
|
||||||
|
return load;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param load the load to set
|
||||||
|
*/
|
||||||
|
public void setLoad(int load) {
|
||||||
|
this.load = load;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ActivityState {
|
||||||
|
private double earliestOperationStart;
|
||||||
|
private double latestOperationStart;
|
||||||
|
private double currentLoad;
|
||||||
|
private double currentCost;
|
||||||
|
private TourActivity act;
|
||||||
|
|
||||||
|
public ActivityState(TourActivity activity){
|
||||||
|
this.earliestOperationStart=activity.getTheoreticalEarliestOperationStartTime();
|
||||||
|
this.latestOperationStart=activity.getTheoreticalLatestOperationStartTime();
|
||||||
|
this.act = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[earliestStart="+earliestOperationStart+"][latestStart="+
|
||||||
|
latestOperationStart+"][currLoad="+currentLoad+"][currCost="+currentCost+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getEarliestOperationStart() {
|
||||||
|
return earliestOperationStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEarliestOperationStart(double earliestOperationStart) {
|
||||||
|
this.earliestOperationStart = earliestOperationStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLatestOperationStart() {
|
||||||
|
return latestOperationStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLatestOperationStart(double latestOperationStart) {
|
||||||
|
this.latestOperationStart = latestOperationStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getCurrentLoad() {
|
||||||
|
return currentLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCurrentLoad(double currentLoad) {
|
||||||
|
this.currentLoad = currentLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getCurrentCost() {
|
||||||
|
return currentCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCurrentCost(double currentCost) {
|
||||||
|
this.currentCost = currentCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
earliestOperationStart = act.getTheoreticalEarliestOperationStartTime();
|
||||||
|
latestOperationStart = act.getTheoreticalLatestOperationStartTime() ;
|
||||||
|
currentLoad = 0.0;
|
||||||
|
currentCost = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Map<TourActivity, ActivityState> activityStates;
|
||||||
|
|
||||||
|
private Map<Service, TourActivity> tourActivities;
|
||||||
|
|
||||||
|
private Map<VehicleRoute, RouteState> routeStates;
|
||||||
|
|
||||||
|
public RouteStates() {
|
||||||
|
activityStates = new HashMap<TourActivity, RouteStates.ActivityState>();
|
||||||
|
tourActivities = new HashMap<Service,TourActivity>();
|
||||||
|
routeStates = new HashMap<VehicleRoute, RouteStates.RouteState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivityState getState(TourActivity act){
|
||||||
|
if(!activityStates.containsKey(act)) return null;
|
||||||
|
return activityStates.get(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearStates(){
|
||||||
|
activityStates.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<TourActivity, ActivityState> getActivityStates() {
|
||||||
|
return activityStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
TourActivity getActivity(Service service, boolean resetState){
|
||||||
|
TourActivity tourActivity = tourActivities.get(service);
|
||||||
|
getState(tourActivity).reset();
|
||||||
|
return tourActivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetRouteStates(){
|
||||||
|
routeStates.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteState getRouteState(VehicleRoute route){
|
||||||
|
RouteState routeState = routeStates.get(route);
|
||||||
|
if(routeState == null){
|
||||||
|
routeState = new RouteState(route);
|
||||||
|
putRouteState(route, routeState);
|
||||||
|
}
|
||||||
|
return routeState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putRouteState(VehicleRoute route, RouteState routeState){
|
||||||
|
routeStates.put(route, routeState);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialiseStateOfJobs(Collection<Job> jobs){
|
||||||
|
for(Job job : jobs){
|
||||||
|
if(job instanceof Service){
|
||||||
|
ServiceActivity service = ServiceActivity.newInstance((Service)job);
|
||||||
|
ActivityState state = new ActivityState(service);
|
||||||
|
tourActivities.put((Service) job, service);
|
||||||
|
activityStates.put(service, state);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
resetRouteStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
207
jsprit-core/src/main/java/algorithms/RuinRadial.java
Normal file
207
jsprit-core/src/main/java/algorithms/RuinRadial.java
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.RandomNumberGeneration;
|
||||||
|
import util.StopWatch;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.SearchStrategyModule;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class RuinRadial implements RuinStrategy {
|
||||||
|
|
||||||
|
private final static String NAME = "radialRuin";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a new creation of instance of ruinRadial
|
||||||
|
* @param vrp
|
||||||
|
* @param fraction TODO
|
||||||
|
* @param jobDistance
|
||||||
|
* @param jobRemover TODO
|
||||||
|
* @param routeUpdater TODO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static RuinRadial newInstance(VehicleRoutingProblem vrp, double fraction, JobDistance jobDistance, JobRemover jobRemover, VehicleRouteUpdater routeUpdater){
|
||||||
|
return new RuinRadial(vrp, fraction, jobDistance, jobRemover, routeUpdater);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class ReferencedJob {
|
||||||
|
private Job job;
|
||||||
|
private double distance;
|
||||||
|
|
||||||
|
public ReferencedJob(Job job, double distance) {
|
||||||
|
super();
|
||||||
|
this.job = job;
|
||||||
|
this.distance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Job getJob() {
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDistance() {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Logger logger = Logger.getLogger(RuinRadial.class);
|
||||||
|
|
||||||
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
|
private double fractionOfAllNodes2beRuined;
|
||||||
|
|
||||||
|
private Map<String, TreeSet<ReferencedJob>> distanceNodeTree = new HashMap<String, TreeSet<ReferencedJob>>();
|
||||||
|
|
||||||
|
private Random random = RandomNumberGeneration.getRandom();
|
||||||
|
|
||||||
|
private JobDistance jobDistance;
|
||||||
|
|
||||||
|
private JobRemover jobRemover;
|
||||||
|
|
||||||
|
private VehicleRouteUpdater routeUpdater;
|
||||||
|
|
||||||
|
public void setRandom(Random random) {
|
||||||
|
this.random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RuinRadial(VehicleRoutingProblem vrp, double fraction, JobDistance jobDistance, JobRemover jobRemover, VehicleRouteUpdater routeUpdater) {
|
||||||
|
super();
|
||||||
|
this.vrp = vrp;
|
||||||
|
this.jobDistance = jobDistance;
|
||||||
|
this.jobRemover = jobRemover;
|
||||||
|
this.routeUpdater = routeUpdater;
|
||||||
|
this.fractionOfAllNodes2beRuined = fraction;
|
||||||
|
calculateDistancesFromJob2Job();
|
||||||
|
logger.info("intialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRuinFraction(double fractionOfAllNodes) {
|
||||||
|
this.fractionOfAllNodes2beRuined = fractionOfAllNodes;
|
||||||
|
logger.info("fraction set " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateDistancesFromJob2Job() {
|
||||||
|
logger.info("preprocess distances between locations ...");
|
||||||
|
StopWatch stopWatch = new StopWatch();
|
||||||
|
stopWatch.start();
|
||||||
|
int nuOfDistancesStored = 0;
|
||||||
|
for (Job i : vrp.getJobs().values()) {
|
||||||
|
TreeSet<ReferencedJob> treeSet = new TreeSet<ReferencedJob>(
|
||||||
|
new Comparator<ReferencedJob>() {
|
||||||
|
@Override
|
||||||
|
public int compare(ReferencedJob o1, ReferencedJob o2) {
|
||||||
|
if (o1.getDistance() <= o2.getDistance()) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
distanceNodeTree.put(i.getId(), treeSet);
|
||||||
|
for (Job j : vrp.getJobs().values()) {
|
||||||
|
double distance = jobDistance.calculateDistance(i, j);
|
||||||
|
ReferencedJob refNode = new ReferencedJob(j, distance);
|
||||||
|
treeSet.add(refNode);
|
||||||
|
nuOfDistancesStored++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stopWatch.stop();
|
||||||
|
logger.info("preprocessing comp-time: " + stopWatch + "; nuOfDistances stored: " + nuOfDistancesStored + "; estimated memory: " +
|
||||||
|
(distanceNodeTree.keySet().size()*64+nuOfDistancesStored*92) + " bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=radialRuin][fraction="+fractionOfAllNodes2beRuined+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
|
if(vehicleRoutes.isEmpty()){
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
}
|
||||||
|
int nOfJobs2BeRemoved = getNuOfJobs2BeRemoved();
|
||||||
|
if (nOfJobs2BeRemoved == 0) {
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
}
|
||||||
|
Job randomJob = pickRandomJob();
|
||||||
|
Collection<Job> unassignedJobs = ruin(vehicleRoutes,randomJob,nOfJobs2BeRemoved);
|
||||||
|
return unassignedJobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved){
|
||||||
|
List<Job> unassignedJobs = new ArrayList<Job>();
|
||||||
|
TreeSet<ReferencedJob> tree = distanceNodeTree.get(targetJob.getId());
|
||||||
|
Iterator<ReferencedJob> descendingIterator = tree.descendingIterator();
|
||||||
|
int counter = 0;
|
||||||
|
while (descendingIterator.hasNext() && counter < nOfJobs2BeRemoved) {
|
||||||
|
ReferencedJob refJob = descendingIterator.next();
|
||||||
|
Job job = refJob.getJob();
|
||||||
|
unassignedJobs.add(job);
|
||||||
|
counter++;
|
||||||
|
boolean removed = false;
|
||||||
|
for (VehicleRoute route : vehicleRoutes) {
|
||||||
|
removed = jobRemover.removeJobWithoutTourUpdate(job, route);
|
||||||
|
if (removed) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(VehicleRoute route : vehicleRoutes){
|
||||||
|
routeUpdater.updateRoute(route);
|
||||||
|
}
|
||||||
|
return unassignedJobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Job pickRandomJob() {
|
||||||
|
int totNuOfJobs = vrp.getJobs().values().size();
|
||||||
|
int randomIndex = random.nextInt(totNuOfJobs);
|
||||||
|
Job job = new ArrayList<Job>(vrp.getJobs().values()).get(randomIndex);
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getNuOfJobs2BeRemoved() {
|
||||||
|
return (int) Math.ceil(vrp.getJobs().values().size()
|
||||||
|
* fractionOfAllNodes2beRuined);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
|
||||||
|
// ruin(vrpSolution.getRoutes());
|
||||||
|
// return vrpSolution;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String getName() {
|
||||||
|
// return NAME;
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
151
jsprit-core/src/main/java/algorithms/RuinRandom.java
Normal file
151
jsprit-core/src/main/java/algorithms/RuinRandom.java
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.RandomNumberGeneration;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ruin strategy that ruins current solution randomly. I.e.
|
||||||
|
* customer are removed randomly from current solution.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
final class RuinRandom implements RuinStrategy {
|
||||||
|
|
||||||
|
public static RuinRandom newInstance(VehicleRoutingProblem vrp, double fraction, JobRemover jobRemover, VehicleRouteUpdater routeUpdater){
|
||||||
|
return new RuinRandom(vrp, fraction, jobRemover, routeUpdater);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Logger logger = Logger.getLogger(RuinRandom.class);
|
||||||
|
|
||||||
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
|
private double fractionOfAllNodes2beRuined;
|
||||||
|
|
||||||
|
private Random random = RandomNumberGeneration.getRandom();
|
||||||
|
|
||||||
|
private JobRemover jobRemover;
|
||||||
|
|
||||||
|
private VehicleRouteUpdater vehicleRouteUpdater;
|
||||||
|
|
||||||
|
public void setRandom(Random random) {
|
||||||
|
this.random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs ruinRandom.
|
||||||
|
*
|
||||||
|
* @param vrp
|
||||||
|
* @param fraction which is the fraction of total c
|
||||||
|
* @param jobRemover
|
||||||
|
* @param vehicleRouteUpdater
|
||||||
|
*/
|
||||||
|
public RuinRandom(VehicleRoutingProblem vrp, double fraction, JobRemover jobRemover, VehicleRouteUpdater vehicleRouteUpdater) {
|
||||||
|
super();
|
||||||
|
this.vrp = vrp;
|
||||||
|
this.jobRemover = jobRemover;
|
||||||
|
this.vehicleRouteUpdater = vehicleRouteUpdater;
|
||||||
|
this.fractionOfAllNodes2beRuined = fraction;
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
logger.info("done");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a fraction of jobs from vehicleRoutes.
|
||||||
|
*
|
||||||
|
* <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
|
List<Job> unassignedJobs = new ArrayList<Job>();
|
||||||
|
int nOfJobs2BeRemoved = selectNuOfJobs2BeRemoved();
|
||||||
|
ruin(vehicleRoutes, nOfJobs2BeRemoved, unassignedJobs);
|
||||||
|
return unassignedJobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes nOfJobs2BeRemoved from vehicleRoutes, including targetJob.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved) {
|
||||||
|
List<Job> unassignedJobs = new ArrayList<Job>();
|
||||||
|
if(targetJob != null){
|
||||||
|
boolean removed = false;
|
||||||
|
for (VehicleRoute route : vehicleRoutes) {
|
||||||
|
removed = jobRemover.removeJobWithoutTourUpdate(targetJob, route);
|
||||||
|
if (removed) {
|
||||||
|
nOfJobs2BeRemoved--;
|
||||||
|
unassignedJobs.add(targetJob);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ruin(vehicleRoutes, nOfJobs2BeRemoved, unassignedJobs);
|
||||||
|
return unassignedJobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRuinFraction(double fractionOfAllNodes2beRuined) {
|
||||||
|
this.fractionOfAllNodes2beRuined = fractionOfAllNodes2beRuined;
|
||||||
|
logger.info("fraction set " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ruin(Collection<VehicleRoute> vehicleRoutes,int nOfJobs2BeRemoved, List<Job> unassignedJobs) {
|
||||||
|
LinkedList<Job> availableJobs = new LinkedList<Job>(vrp.getJobs().values());
|
||||||
|
for (int i = 0; i < nOfJobs2BeRemoved; i++) {
|
||||||
|
Job job = pickRandomJob(availableJobs);
|
||||||
|
unassignedJobs.add(job);
|
||||||
|
availableJobs.remove(job);
|
||||||
|
for (VehicleRoute route : vehicleRoutes) {
|
||||||
|
boolean removed = jobRemover.removeJobWithoutTourUpdate(job, route);
|
||||||
|
if (removed) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateRoutes(vehicleRoutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRoutes(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
|
for(VehicleRoute route : vehicleRoutes){
|
||||||
|
vehicleRouteUpdater.updateRoute(route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=randomRuin][fraction="+fractionOfAllNodes2beRuined+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private Job pickRandomJob(LinkedList<Job> availableJobs) {
|
||||||
|
int randomIndex = random.nextInt(availableJobs.size());
|
||||||
|
return availableJobs.get(randomIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int selectNuOfJobs2BeRemoved() {
|
||||||
|
return (int) Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
47
jsprit-core/src/main/java/algorithms/RuinStrategy.java
Normal file
47
jsprit-core/src/main/java/algorithms/RuinStrategy.java
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface RuinStrategy {
|
||||||
|
|
||||||
|
public static interface RuinListener {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ruins a current solution, i.e. removes jobs from service providers and
|
||||||
|
* returns a collection of these removed, and thus unassigned, jobs.
|
||||||
|
*
|
||||||
|
* @param vehicleRoutes
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes);
|
||||||
|
|
||||||
|
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
|
||||||
|
interface RuinStrategyFactory {
|
||||||
|
|
||||||
|
public RuinStrategy createStrategy(VehicleRoutingProblem vrp);
|
||||||
|
|
||||||
|
}
|
||||||
65
jsprit-core/src/main/java/algorithms/SchrimpfFactory.java
Normal file
65
jsprit-core/src/main/java/algorithms/SchrimpfFactory.java
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingAlgorithm;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.io.AlgorithmConfig;
|
||||||
|
import basics.io.AlgorithmConfigXmlReader;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory that creates the {@link VehicleRoutingAlgorithm} as proposed by Schrimpf et al., 2000 with the following parameters:
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* R&R_random (prob=0.5, F=0.5);
|
||||||
|
* R&R_radial (prob=0.5, F=0.3);
|
||||||
|
* threshold-accepting with exponentialDecayFunction (alpha=0.1, warmup-iterations=100);
|
||||||
|
* nuOfIterations=2000
|
||||||
|
*
|
||||||
|
* <p>Gerhard Schrimpf, Johannes Schneider, Hermann Stamm- Wilbrandt, and Gunter Dueck.
|
||||||
|
* Record breaking optimization results using the ruin and recreate principle.
|
||||||
|
* Journal of Computational Physics, 159(2):139 – 171, 2000. ISSN 0021-9991. doi: 10.1006/jcph.1999. 6413.
|
||||||
|
* URL http://www.sciencedirect.com/science/article/ pii/S0021999199964136
|
||||||
|
*
|
||||||
|
* <p>algorithm-xml-config is available at src/main/resources/schrimpf.xml.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SchrimpfFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the {@link VehicleRoutingAlgorithm}.
|
||||||
|
*
|
||||||
|
* @param vrp
|
||||||
|
* @return algorithm
|
||||||
|
*/
|
||||||
|
public VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp){
|
||||||
|
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
||||||
|
URL resource = this.getClass().getClassLoader().getResource("schrimpf.xml");
|
||||||
|
new AlgorithmConfigXmlReader(algorithmConfig).read(resource.getPath());
|
||||||
|
return VehicleRoutingAlgorithms.createAlgorithm(vrp, algorithmConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
63
jsprit-core/src/main/java/algorithms/ScoredJob.java
Normal file
63
jsprit-core/src/main/java/algorithms/ScoredJob.java
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ScoredJob {
|
||||||
|
|
||||||
|
private final Job job;
|
||||||
|
|
||||||
|
private final double score;
|
||||||
|
|
||||||
|
private final InsertionData insertionData;
|
||||||
|
|
||||||
|
private final VehicleRoute route;
|
||||||
|
|
||||||
|
public ScoredJob(final Job job, final double score, final InsertionData insertionData, final VehicleRoute route) {
|
||||||
|
super();
|
||||||
|
this.job = job;
|
||||||
|
this.score = score;
|
||||||
|
this.insertionData = insertionData;
|
||||||
|
this.route = route;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InsertionData getInsertionData() {
|
||||||
|
return insertionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoute getRoute() {
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Job getJob() {
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScore() {
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
51
jsprit-core/src/main/java/algorithms/SolutionVerifier.java
Normal file
51
jsprit-core/src/main/java/algorithms/SolutionVerifier.java
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.AlgorithmEndsListener;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class SolutionVerifier implements AlgorithmEndsListener{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
|
||||||
|
for(VehicleRoutingProblemSolution solution : solutions){
|
||||||
|
Set<Job> jobsInSolution = new HashSet<Job>();
|
||||||
|
for(VehicleRoute route : solution.getRoutes()){
|
||||||
|
jobsInSolution.addAll(route.getTourActivities().getJobs());
|
||||||
|
}
|
||||||
|
if(jobsInSolution.size() != problem.getJobs().size()){
|
||||||
|
throw new IllegalStateException("we are at the end of the algorithm and still have not found a valid solution." +
|
||||||
|
"This cannot be.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class TourConstraintEngine {
|
||||||
|
|
||||||
|
// void ini(VehicleRoute route, Job job){
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
91
jsprit-core/src/main/java/algorithms/TourStateUpdater.java
Normal file
91
jsprit-core/src/main/java/algorithms/TourStateUpdater.java
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates tour state, i.e. the tour as well as each activity in that tour has a state such as currentLoad, currentCost, earliestOperationTime and
|
||||||
|
* latestOperationTime. Each time the tour is changed (for instance by removing or adding an activity), tour and activity states
|
||||||
|
* might change, thus this updater updates activity states.
|
||||||
|
* This includes:
|
||||||
|
* - update load and totalCost at tour-level
|
||||||
|
* - update currentLoad and currentCost at activity-level
|
||||||
|
* - update earliest- and latestOperationStart values at activity-level
|
||||||
|
*
|
||||||
|
* If ensureFeasibility is true, then it additionally checks whether the earliestOperationStartTime is higher than the latestOperationStartTime.
|
||||||
|
* If it is, it returns a false value to indicate that the tour is not feasible. This makes only sense for hard-timewindows.
|
||||||
|
*
|
||||||
|
* If softTimeWindow is set to true, latestOperationStartTimes are not updated and the tour is always feasible.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TourStateUpdater implements VehicleRouteUpdater{
|
||||||
|
|
||||||
|
// public final static Counter counter = new Counter("#updateTWProcesses: ");
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(TourStateUpdater.class);
|
||||||
|
|
||||||
|
private boolean ensureFeasibility = true;
|
||||||
|
|
||||||
|
private UpdateTourStatesForwardInTime forwardUpdate;
|
||||||
|
|
||||||
|
private UpdateTourStatesBackwardInTime backwardUpdate;
|
||||||
|
|
||||||
|
private boolean updateTimeWindows = true;
|
||||||
|
|
||||||
|
private RouteStates actStates;
|
||||||
|
|
||||||
|
public TourStateUpdater(RouteStates activityStates, VehicleRoutingTransportCosts costs, VehicleRoutingActivityCosts costFunction) {
|
||||||
|
super();
|
||||||
|
forwardUpdate = new UpdateTourStatesForwardInTime(costs, costs, costFunction);
|
||||||
|
backwardUpdate = new UpdateTourStatesBackwardInTime(costs);
|
||||||
|
actStates=activityStates;
|
||||||
|
forwardUpdate.setActivityStates(actStates);
|
||||||
|
backwardUpdate.setActivityStates(actStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean updateRoute(VehicleRoute vehicleRoute) {
|
||||||
|
if(updateTimeWindows){
|
||||||
|
backwardUpdate.checkFeasibility = ensureFeasibility;
|
||||||
|
backwardUpdate.updateRoute(vehicleRoute);
|
||||||
|
}
|
||||||
|
forwardUpdate.updateRoute(vehicleRoute);
|
||||||
|
boolean tourIsFeasible = true;
|
||||||
|
|
||||||
|
return tourIsFeasible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeWindowUpdate(boolean updateTimeWindows) {
|
||||||
|
this.updateTimeWindows = updateTimeWindows;
|
||||||
|
logger.info("set timeWindowUpdate to " + updateTimeWindows);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnsureFeasibility(boolean ensureFeasibility) {
|
||||||
|
this.ensureFeasibility = ensureFeasibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import algorithms.RouteStates.ActivityState;
|
||||||
|
import basics.costs.BackwardTransportTime;
|
||||||
|
import basics.route.Start;
|
||||||
|
import basics.route.TourActivities;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class UpdateTourStatesBackwardInTime implements VehicleRouteUpdater{
|
||||||
|
|
||||||
|
// public static Counter counter = new Counter("#updateTWProcesses: ");
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(UpdateTourStatesBackwardInTime.class);
|
||||||
|
|
||||||
|
public boolean checkFeasibility = true;
|
||||||
|
|
||||||
|
private BackwardTransportTime transportTime;
|
||||||
|
|
||||||
|
private RouteStates actStates;
|
||||||
|
|
||||||
|
public void setActivityStates(RouteStates actStates){
|
||||||
|
this.actStates = actStates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActivityState state(TourActivity act){
|
||||||
|
return actStates.getState(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateTourStatesBackwardInTime(BackwardTransportTime transportTime) {
|
||||||
|
super();
|
||||||
|
this.transportTime = transportTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean updateRoute(VehicleRoute vehicleRoute) {
|
||||||
|
boolean ok = update(vehicleRoute);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private boolean update(VehicleRoute vehicleRoute) {
|
||||||
|
TourActivities tour = vehicleRoute.getTourActivities();
|
||||||
|
int tourSize = tour.getActivities().size();
|
||||||
|
Iterator<TourActivity> reverseActIter = vehicleRoute.getTourActivities().reverseActivityIterator();
|
||||||
|
TourActivity prevAct;
|
||||||
|
boolean feasible = true;
|
||||||
|
prevAct = vehicleRoute.getEnd();
|
||||||
|
double startAtPrevAct = prevAct.getTheoreticalLatestOperationStartTime();
|
||||||
|
int count = 0;
|
||||||
|
while(reverseActIter.hasNext()){
|
||||||
|
TourActivity currAct = reverseActIter.next();
|
||||||
|
|
||||||
|
double latestOperationStartTime = latestOperationStartTime(vehicleRoute, prevAct, currAct, startAtPrevAct);
|
||||||
|
ActivityState state = state(currAct);
|
||||||
|
state.setLatestOperationStart(latestOperationStartTime);
|
||||||
|
prevAct = currAct;
|
||||||
|
startAtPrevAct = latestOperationStartTime;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
// Start start = vehicleRoute.getStart();
|
||||||
|
// double latestOperationStartTime = latestOperationStartTime(vehicleRoute, prevAct, start, startAtPrevAct);
|
||||||
|
assert count == tourSize;
|
||||||
|
return feasible;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double latestOperationStartTime(VehicleRoute vehicleRoute,
|
||||||
|
TourActivity prevAct, TourActivity currAct, double startAtPrevAct) {
|
||||||
|
double latestDepTimeAtCurrAct = startAtPrevAct - transportTime.getBackwardTransportTime(currAct.getLocationId(), prevAct.getLocationId(), startAtPrevAct, vehicleRoute.getDriver(),vehicleRoute.getVehicle());
|
||||||
|
double potentialLatestOperationStartTimeAtCurrAct = latestDepTimeAtCurrAct - currAct.getOperationTime();
|
||||||
|
double latestOperationStartTime = Math.min(currAct.getTheoreticalLatestOperationStartTime(), potentialLatestOperationStartTimeAtCurrAct);
|
||||||
|
return latestOperationStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import algorithms.RouteStates.ActivityState;
|
||||||
|
import basics.costs.ForwardTransportCost;
|
||||||
|
import basics.costs.ForwardTransportTime;
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
import basics.route.Driver;
|
||||||
|
import basics.route.End;
|
||||||
|
import basics.route.ServiceActivity;
|
||||||
|
import basics.route.TourActivities;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author sschroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class UpdateTourStatesForwardInTime implements VehicleRouteUpdater{
|
||||||
|
|
||||||
|
// public static Counter counter = new Counter("#updateTWProcesses: ");
|
||||||
|
private static Logger log = Logger.getLogger(UpdateTourStatesForwardInTime.class);
|
||||||
|
|
||||||
|
public boolean checkFeasibility = true;
|
||||||
|
|
||||||
|
private VehicleRoutingActivityCosts activityCost;
|
||||||
|
|
||||||
|
private ForwardTransportTime transportTime;
|
||||||
|
|
||||||
|
private ForwardTransportCost transportCost;
|
||||||
|
|
||||||
|
private RouteStates routeStates;
|
||||||
|
|
||||||
|
private boolean activityStatesSet = false;
|
||||||
|
|
||||||
|
public void setActivityStates(RouteStates actStates){
|
||||||
|
this.routeStates = actStates;
|
||||||
|
activityStatesSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActivityState state(TourActivity act){
|
||||||
|
return routeStates.getState(act);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateTourStatesForwardInTime(ForwardTransportTime transportTime, ForwardTransportCost transportCost, VehicleRoutingActivityCosts activityCost) {
|
||||||
|
super();
|
||||||
|
this.transportTime = transportTime;
|
||||||
|
this.transportCost = transportCost;
|
||||||
|
this.activityCost = activityCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean updateRoute(VehicleRoute vehicleRoute) {
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().reset();
|
||||||
|
|
||||||
|
Vehicle vehicle = vehicleRoute.getVehicle();
|
||||||
|
Driver driver = vehicleRoute.getDriver();
|
||||||
|
|
||||||
|
TourActivity prevAct = vehicleRoute.getStart();
|
||||||
|
|
||||||
|
double startAtPrevAct = vehicleRoute.getStart().getEndTime();
|
||||||
|
|
||||||
|
double totalOperationCost = 0.0;
|
||||||
|
int totalLoadPicked = 0;
|
||||||
|
int currentLoadState = 0;
|
||||||
|
|
||||||
|
for(TourActivity currentAct : vehicleRoute.getTourActivities().getActivities()){
|
||||||
|
totalLoadPicked += getPickedLoad(currentAct);
|
||||||
|
currentLoadState += getCapDemand(currentAct);
|
||||||
|
|
||||||
|
double transportTime = this.transportTime.getTransportTime(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle);
|
||||||
|
|
||||||
|
double arrivalTimeAtCurrAct = startAtPrevAct + transportTime;
|
||||||
|
double operationStartTime = Math.max(currentAct.getTheoreticalEarliestOperationStartTime(), arrivalTimeAtCurrAct);
|
||||||
|
|
||||||
|
double operationEndTime = operationStartTime + currentAct.getOperationTime();
|
||||||
|
|
||||||
|
currentAct.setArrTime(arrivalTimeAtCurrAct);
|
||||||
|
currentAct.setEndTime(operationEndTime);
|
||||||
|
|
||||||
|
double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle);
|
||||||
|
double actCost = activityCost.getActivityCost(currentAct, arrivalTimeAtCurrAct, driver, vehicle);
|
||||||
|
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost);
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost);
|
||||||
|
|
||||||
|
totalOperationCost += transportCost;
|
||||||
|
totalOperationCost += actCost;
|
||||||
|
|
||||||
|
if(activityStatesSet){
|
||||||
|
ActivityState currentState = state(currentAct);
|
||||||
|
currentState.setEarliestOperationStart(operationStartTime);
|
||||||
|
currentState.setCurrentLoad(currentLoadState);
|
||||||
|
currentState.setCurrentCost(totalOperationCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
prevAct = currentAct;
|
||||||
|
startAtPrevAct = operationEndTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
End currentAct = vehicleRoute.getEnd();
|
||||||
|
double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle);
|
||||||
|
double transportTime = this.transportTime.getTransportTime(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle);
|
||||||
|
double arrivalTimeAtCurrAct = startAtPrevAct + transportTime;
|
||||||
|
|
||||||
|
currentAct.setArrTime(arrivalTimeAtCurrAct);
|
||||||
|
currentAct.setEndTime(arrivalTimeAtCurrAct);
|
||||||
|
|
||||||
|
totalOperationCost += transportCost;
|
||||||
|
|
||||||
|
routeStates.getRouteState(vehicleRoute).setCosts(totalOperationCost);
|
||||||
|
routeStates.getRouteState(vehicleRoute).setLoad(totalLoadPicked);
|
||||||
|
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost);
|
||||||
|
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getDriver());
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getVehicle());
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getCapDemand(TourActivity currentAct) {
|
||||||
|
return currentAct.getCapacityDemand();
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getPickedLoad(TourActivity currentAct) {
|
||||||
|
if(currentAct instanceof ServiceActivity){
|
||||||
|
return currentAct.getCapacityDemand();
|
||||||
|
}
|
||||||
|
// else if(currentAct instanceof Pickup){
|
||||||
|
// return currentAct.getCapacityDemand();
|
||||||
|
// }
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleImpl;
|
||||||
|
import basics.route.VehicleImpl.VehicleType;
|
||||||
|
|
||||||
|
interface VehicleFleetManager {
|
||||||
|
|
||||||
|
public static class TypeKey {
|
||||||
|
|
||||||
|
public final VehicleType type;
|
||||||
|
public final String locationId;
|
||||||
|
|
||||||
|
public TypeKey(VehicleType type, String locationId) {
|
||||||
|
super();
|
||||||
|
this.type = type;
|
||||||
|
this.locationId = locationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result
|
||||||
|
+ ((locationId == null) ? 0 : locationId.hashCode());
|
||||||
|
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
TypeKey other = (TypeKey) obj;
|
||||||
|
if (locationId == null) {
|
||||||
|
if (other.locationId != null)
|
||||||
|
return false;
|
||||||
|
} else if (!locationId.equals(other.locationId))
|
||||||
|
return false;
|
||||||
|
if (type == null) {
|
||||||
|
if (other.type != null)
|
||||||
|
return false;
|
||||||
|
} else if (!type.equals(other.type))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Vehicle getEmptyVehicle(TypeKey typeId);
|
||||||
|
|
||||||
|
public abstract Collection<TypeKey> getAvailableVehicleTypes();
|
||||||
|
|
||||||
|
public abstract void lock(Vehicle vehicle);
|
||||||
|
|
||||||
|
public abstract void unlock(Vehicle vehicle);
|
||||||
|
|
||||||
|
public abstract Collection<TypeKey> getAvailableVehicleTypes(TypeKey withoutThisType);
|
||||||
|
|
||||||
|
public abstract boolean isLocked(Vehicle vehicle);
|
||||||
|
|
||||||
|
public abstract void unlockAll();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleImpl.NoVehicle;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class VehicleFleetManagerImpl implements VehicleFleetManager {
|
||||||
|
|
||||||
|
public VehicleFleetManagerImpl newInstance(Collection<Vehicle> vehicles){
|
||||||
|
return new VehicleFleetManagerImpl(vehicles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VehicleFleetManager createDefaultFleetManager() {
|
||||||
|
return new DefaultFleetManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DefaultFleetManager extends VehicleFleetManagerImpl {
|
||||||
|
|
||||||
|
public DefaultFleetManager() {
|
||||||
|
super(Collections.EMPTY_LIST);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TypeContainer {
|
||||||
|
|
||||||
|
private TypeKey type;
|
||||||
|
|
||||||
|
private ArrayList<Vehicle> vehicleList;
|
||||||
|
|
||||||
|
public TypeContainer(TypeKey type) {
|
||||||
|
super();
|
||||||
|
this.type = type;
|
||||||
|
vehicleList = new ArrayList<Vehicle>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(Vehicle vehicle){
|
||||||
|
if(vehicleList.contains(vehicle)){
|
||||||
|
throw new IllegalStateException("cannot add vehicle twice " + vehicle.getId());
|
||||||
|
}
|
||||||
|
vehicleList.add(vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(Vehicle vehicle){
|
||||||
|
vehicleList.remove(vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vehicle getVehicle() {
|
||||||
|
return vehicleList.get(0);
|
||||||
|
// return vehicleList.getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return vehicleList.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(VehicleFleetManagerImpl.class);
|
||||||
|
|
||||||
|
private Collection<Vehicle> vehicles;
|
||||||
|
|
||||||
|
private Set<Vehicle> lockedVehicles;
|
||||||
|
|
||||||
|
private Map<TypeKey,TypeContainer> typeMapOfAvailableVehicles;
|
||||||
|
|
||||||
|
public VehicleFleetManagerImpl(Collection<Vehicle> vehicles) {
|
||||||
|
super();
|
||||||
|
this.vehicles = vehicles;
|
||||||
|
this.lockedVehicles = new HashSet<Vehicle>();
|
||||||
|
makeMap();
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleFleetManagerImpl(Collection<Vehicle> vehicles, Collection<Vehicle> lockedVehicles) {
|
||||||
|
this.vehicles = vehicles;
|
||||||
|
makeMap();
|
||||||
|
this.lockedVehicles = new HashSet<Vehicle>();
|
||||||
|
for(Vehicle v : lockedVehicles){
|
||||||
|
lock(v);
|
||||||
|
}
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=finiteVehicles]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void makeMap() {
|
||||||
|
typeMapOfAvailableVehicles = new HashMap<TypeKey, TypeContainer>();
|
||||||
|
for(Vehicle v : vehicles){
|
||||||
|
addVehicle(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addVehicle(Vehicle v) {
|
||||||
|
if(v.getType() == null){
|
||||||
|
throw new IllegalStateException("vehicle needs type");
|
||||||
|
}
|
||||||
|
// String typeId = v.getType().typeId;
|
||||||
|
TypeKey typeKey = new TypeKey(v.getType(),v.getLocationId());
|
||||||
|
if(!typeMapOfAvailableVehicles.containsKey(typeKey)){
|
||||||
|
typeMapOfAvailableVehicles.put(typeKey, new TypeContainer(typeKey));
|
||||||
|
}
|
||||||
|
typeMapOfAvailableVehicles.get(typeKey).add(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeVehicle(Vehicle v){
|
||||||
|
TypeKey key = new TypeKey(v.getType(),v.getLocationId());
|
||||||
|
if(typeMapOfAvailableVehicles.containsKey(key)){
|
||||||
|
typeMapOfAvailableVehicles.get(key).remove(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#getEmptyVehicle(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Vehicle getEmptyVehicle(TypeKey typeId){
|
||||||
|
Vehicle v = null;
|
||||||
|
if(typeMapOfAvailableVehicles.containsKey(typeId)){
|
||||||
|
v = typeMapOfAvailableVehicles.get(typeId).getVehicle();
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#getAvailableVehicleTypes()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<TypeKey> getAvailableVehicleTypes(){
|
||||||
|
List<TypeKey> types = new ArrayList<TypeKey>();
|
||||||
|
for(TypeKey key : typeMapOfAvailableVehicles.keySet()){
|
||||||
|
if(!typeMapOfAvailableVehicles.get(key).isEmpty()){
|
||||||
|
types.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#lock(org.matsim.contrib.freight.vrp.basics.Vehicle)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void lock(Vehicle vehicle){
|
||||||
|
if(vehicles.isEmpty() || vehicle instanceof NoVehicle){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean locked = lockedVehicles.add(vehicle);
|
||||||
|
removeVehicle(vehicle);
|
||||||
|
if(!locked){
|
||||||
|
throw new IllegalStateException("cannot lock vehicle twice " + vehicle.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#unlock(org.matsim.contrib.freight.vrp.basics.Vehicle)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void unlock(Vehicle vehicle){
|
||||||
|
if(vehicles.isEmpty() || vehicle instanceof NoVehicle){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(vehicle == null) return;
|
||||||
|
lockedVehicles.remove(vehicle);
|
||||||
|
addVehicle(vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#getAvailableVehicleTypes(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<TypeKey> getAvailableVehicleTypes(TypeKey withoutThisType) {
|
||||||
|
List<TypeKey> types = new ArrayList<TypeKey>();
|
||||||
|
for(TypeKey typeKey : typeMapOfAvailableVehicles.keySet()){
|
||||||
|
if(typeKey.equals(withoutThisType)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!typeMapOfAvailableVehicles.get(typeKey).isEmpty()){
|
||||||
|
types.add(typeKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#isLocked(org.matsim.contrib.freight.vrp.basics.Vehicle)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isLocked(Vehicle vehicle) {
|
||||||
|
return lockedVehicles.contains(vehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#unlockAll()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void unlockAll() {
|
||||||
|
Collection<Vehicle> locked = new ArrayList<Vehicle>(lockedVehicles);
|
||||||
|
for(Vehicle v : locked){
|
||||||
|
unlock(v);
|
||||||
|
}
|
||||||
|
if(!lockedVehicles.isEmpty()){
|
||||||
|
throw new IllegalStateException("no vehicle must be locked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sizeOfLockedVehicles(){
|
||||||
|
return lockedVehicles.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updater that updates a vehicleRoute, e.g. the total costs or the time-windows.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
interface VehicleRouteUpdater {
|
||||||
|
|
||||||
|
public boolean updateRoute(VehicleRoute vehicleRoute);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,870 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.configuration.HierarchicalConfiguration;
|
||||||
|
import org.apache.commons.configuration.XMLConfiguration;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.RouteUtils;
|
||||||
|
import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractInsertionKey;
|
||||||
|
import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractKey;
|
||||||
|
import algorithms.VehicleRoutingAlgorithms.TypedMap.AcceptorKey;
|
||||||
|
import algorithms.VehicleRoutingAlgorithms.TypedMap.RuinStrategyKey;
|
||||||
|
import algorithms.VehicleRoutingAlgorithms.TypedMap.SelectorKey;
|
||||||
|
import algorithms.VehicleRoutingAlgorithms.TypedMap.StrategyModuleKey;
|
||||||
|
import algorithms.acceptors.AcceptNewIfBetterThanWorst;
|
||||||
|
import algorithms.acceptors.AcceptNewRemoveFirst;
|
||||||
|
import algorithms.acceptors.SchrimpfAcceptance;
|
||||||
|
import algorithms.acceptors.SolutionAcceptor;
|
||||||
|
import algorithms.selectors.SelectBest;
|
||||||
|
import algorithms.selectors.SelectRandomly;
|
||||||
|
import algorithms.selectors.SolutionSelector;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.VehicleRoutingAlgorithm;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblem.FleetSize;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.AlgorithmStartsListener;
|
||||||
|
import basics.algo.InsertionListener;
|
||||||
|
import basics.algo.SearchStrategy;
|
||||||
|
import basics.algo.SearchStrategyManager;
|
||||||
|
import basics.algo.SearchStrategyModule;
|
||||||
|
import basics.algo.SearchStrategyModuleListener;
|
||||||
|
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
||||||
|
import basics.algo.VehicleRoutingAlgorithmListeners.Priority;
|
||||||
|
import basics.io.AlgorithmConfig;
|
||||||
|
import basics.io.AlgorithmConfigXmlReader;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class VehicleRoutingAlgorithms {
|
||||||
|
|
||||||
|
static class TypedMap {
|
||||||
|
|
||||||
|
static interface AbstractKey<K> {
|
||||||
|
|
||||||
|
Class<K> getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AcceptorKey implements AbstractKey<SolutionAcceptor>{
|
||||||
|
|
||||||
|
private ModKey modKey;
|
||||||
|
|
||||||
|
public AcceptorKey(ModKey modKey) {
|
||||||
|
super();
|
||||||
|
this.modKey = modKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result
|
||||||
|
+ ((modKey == null) ? 0 : modKey.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (!(obj instanceof AcceptorKey))
|
||||||
|
return false;
|
||||||
|
AcceptorKey other = (AcceptorKey) obj;
|
||||||
|
if (modKey == null) {
|
||||||
|
if (other.modKey != null)
|
||||||
|
return false;
|
||||||
|
} else if (!modKey.equals(other.modKey))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<SolutionAcceptor> getType() {
|
||||||
|
return SolutionAcceptor.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SelectorKey implements AbstractKey<SolutionSelector>{
|
||||||
|
|
||||||
|
private ModKey modKey;
|
||||||
|
|
||||||
|
public SelectorKey(ModKey modKey) {
|
||||||
|
super();
|
||||||
|
this.modKey = modKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result
|
||||||
|
+ ((modKey == null) ? 0 : modKey.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
SelectorKey other = (SelectorKey) obj;
|
||||||
|
if (modKey == null) {
|
||||||
|
if (other.modKey != null)
|
||||||
|
return false;
|
||||||
|
} else if (!modKey.equals(other.modKey))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<SolutionSelector> getType() {
|
||||||
|
return SolutionSelector.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StrategyModuleKey implements AbstractKey<SearchStrategyModule>{
|
||||||
|
|
||||||
|
private ModKey modKey;
|
||||||
|
|
||||||
|
public StrategyModuleKey(ModKey modKey) {
|
||||||
|
super();
|
||||||
|
this.modKey = modKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result
|
||||||
|
+ ((modKey == null) ? 0 : modKey.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
StrategyModuleKey other = (StrategyModuleKey) obj;
|
||||||
|
if (modKey == null) {
|
||||||
|
if (other.modKey != null)
|
||||||
|
return false;
|
||||||
|
} else if (!modKey.equals(other.modKey))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<SearchStrategyModule> getType() {
|
||||||
|
return SearchStrategyModule.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RuinStrategyKey implements AbstractKey<RuinStrategy>{
|
||||||
|
|
||||||
|
private ModKey modKey;
|
||||||
|
|
||||||
|
public RuinStrategyKey(ModKey modKey) {
|
||||||
|
super();
|
||||||
|
this.modKey = modKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result
|
||||||
|
+ ((modKey == null) ? 0 : modKey.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
RuinStrategyKey other = (RuinStrategyKey) obj;
|
||||||
|
if (modKey == null) {
|
||||||
|
if (other.modKey != null)
|
||||||
|
return false;
|
||||||
|
} else if (!modKey.equals(other.modKey))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<RuinStrategy> getType() {
|
||||||
|
return RuinStrategy.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AbstractInsertionKey implements AbstractKey<AbstractInsertionStrategy>{
|
||||||
|
|
||||||
|
private ModKey modKey;
|
||||||
|
|
||||||
|
public AbstractInsertionKey(ModKey modKey) {
|
||||||
|
super();
|
||||||
|
this.modKey = modKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result
|
||||||
|
+ ((modKey == null) ? 0 : modKey.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
AbstractInsertionKey other = (AbstractInsertionKey) obj;
|
||||||
|
if (modKey == null) {
|
||||||
|
if (other.modKey != null)
|
||||||
|
return false;
|
||||||
|
} else if (!modKey.equals(other.modKey))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<AbstractInsertionStrategy> getType() {
|
||||||
|
return AbstractInsertionStrategy.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<AbstractKey<?>, Object> map = new HashMap<AbstractKey<?>, Object>();
|
||||||
|
|
||||||
|
public <T> T get(AbstractKey<T> key) {
|
||||||
|
if(map.get(key) == null) return null;
|
||||||
|
return key.getType().cast(map.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T put(AbstractKey<T> key, T value) {
|
||||||
|
return key.getType().cast(map.put(key, key.getType().cast(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<AbstractKey<?>> keySet(){
|
||||||
|
return map.keySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ModKey {
|
||||||
|
private String name;
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
public ModKey(String name, String id) {
|
||||||
|
super();
|
||||||
|
this.name = name;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||||
|
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
ModKey other = (ModKey) obj;
|
||||||
|
if (id == null) {
|
||||||
|
if (other.id != null)
|
||||||
|
return false;
|
||||||
|
} else if (!id.equals(other.id))
|
||||||
|
return false;
|
||||||
|
if (name == null) {
|
||||||
|
if (other.name != null)
|
||||||
|
return false;
|
||||||
|
} else if (!name.equals(other.name))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(VehicleRoutingAlgorithms.class);
|
||||||
|
|
||||||
|
private VehicleRoutingAlgorithms(){}
|
||||||
|
|
||||||
|
public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp, final AlgorithmConfig algorithmConfig){
|
||||||
|
return createAlgo(vrp,algorithmConfig.getXMLConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, final XMLConfiguration config){
|
||||||
|
return createAlgo(vrp,config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, final String configFileName){
|
||||||
|
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
||||||
|
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
|
||||||
|
xmlReader.read(configFileName);
|
||||||
|
return createAlgo(vrp,algorithmConfig.getXMLConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static VehicleRoutingAlgorithm createAlgo(final VehicleRoutingProblem vrp, XMLConfiguration config){
|
||||||
|
|
||||||
|
//fleetmanager
|
||||||
|
final VehicleFleetManager vehicleFleetManager;
|
||||||
|
if(vrp.getFleetSize().equals(FleetSize.INFINITE)){
|
||||||
|
vehicleFleetManager = new InfiniteVehicles(vrp.getVehicles());
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(vrp.getFleetSize().equals(FleetSize.FINITE)){
|
||||||
|
vehicleFleetManager = new VehicleFleetManagerImpl(vrp.getVehicles());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw new IllegalStateException("fleet size can only be infinite or finite. " +
|
||||||
|
"makes sure your config file contains one of these options");
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<PrioritizedVRAListener> algorithmListeners = new HashSet<PrioritizedVRAListener>();
|
||||||
|
List<InsertionListener> insertionListeners = new ArrayList<InsertionListener>();
|
||||||
|
|
||||||
|
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, new SolutionVerifier()));
|
||||||
|
|
||||||
|
RouteStates routeStates = new RouteStates();
|
||||||
|
routeStates.initialiseStateOfJobs(vrp.getJobs().values());
|
||||||
|
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, routeStates));
|
||||||
|
|
||||||
|
TypedMap definedClasses = new TypedMap();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initial solution - construction
|
||||||
|
*/
|
||||||
|
AlgorithmStartsListener createInitialSolution = createInitialSolution(config,vrp,vehicleFleetManager,routeStates,algorithmListeners,definedClasses);
|
||||||
|
if(createInitialSolution != null) algorithmListeners.add(new PrioritizedVRAListener(Priority.MEDIUM, createInitialSolution));
|
||||||
|
|
||||||
|
int solutionMemory = config.getInt("strategy.memory");
|
||||||
|
SearchStrategyManager searchStratManager = new SearchStrategyManager();
|
||||||
|
List<HierarchicalConfiguration> strategyConfigs = config.configurationsAt("strategy.searchStrategies.searchStrategy");
|
||||||
|
for(HierarchicalConfiguration strategyConfig : strategyConfigs){
|
||||||
|
String name = getName(strategyConfig);
|
||||||
|
SolutionAcceptor acceptor = getAcceptor(strategyConfig,vrp,algorithmListeners,definedClasses,solutionMemory);
|
||||||
|
SolutionSelector selector = getSelector(strategyConfig,vrp,algorithmListeners,definedClasses);
|
||||||
|
SearchStrategy strategy = new SearchStrategy(selector, acceptor);
|
||||||
|
strategy.setName(name);
|
||||||
|
List<HierarchicalConfiguration> modulesConfig = strategyConfig.configurationsAt("modules.module");
|
||||||
|
for(HierarchicalConfiguration moduleConfig : modulesConfig){
|
||||||
|
SearchStrategyModule module = buildModule(moduleConfig,vrp,vehicleFleetManager,routeStates,algorithmListeners,definedClasses);
|
||||||
|
strategy.addModule(module);
|
||||||
|
}
|
||||||
|
searchStratManager.addStrategy(strategy, strategyConfig.getDouble("probability"));
|
||||||
|
}
|
||||||
|
VehicleRoutingAlgorithm metaAlgorithm = new VehicleRoutingAlgorithm(vrp, searchStratManager);
|
||||||
|
if(config.containsKey("iterations")){
|
||||||
|
metaAlgorithm.setNuOfIterations(config.getInt("iterations"));
|
||||||
|
}
|
||||||
|
registerListeners(metaAlgorithm,algorithmListeners);
|
||||||
|
registerInsertionListeners(definedClasses,insertionListeners);
|
||||||
|
return metaAlgorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void registerInsertionListeners(TypedMap definedClasses, List<InsertionListener> insertionListeners) {
|
||||||
|
for(AbstractKey<?> key : definedClasses.keySet()){
|
||||||
|
if(key instanceof AbstractInsertionKey){
|
||||||
|
AbstractInsertionKey insertionKey = (AbstractInsertionKey) key;
|
||||||
|
AbstractInsertionStrategy insertionStrategy = definedClasses.get(insertionKey);
|
||||||
|
for(InsertionListener l : insertionListeners){
|
||||||
|
// log.info("add insertionListener " + l + " to " + insertionStrategy);
|
||||||
|
insertionStrategy.addListener(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// log.warn("cannot register insertion listeners yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getName(HierarchicalConfiguration strategyConfig) {
|
||||||
|
if(strategyConfig.containsKey("[@name]")){
|
||||||
|
return strategyConfig.getString("[@name]");
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void registerListeners(VehicleRoutingAlgorithm metaAlgorithm, Set<PrioritizedVRAListener> algorithmListeners) {
|
||||||
|
metaAlgorithm.getAlgorithmListeners().addAll(algorithmListeners);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, RouteStates activityStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses) {
|
||||||
|
List<HierarchicalConfiguration> modConfigs = config.configurationsAt("construction.insertion");
|
||||||
|
if(modConfigs == null) return null;
|
||||||
|
if(modConfigs.isEmpty()) return null;
|
||||||
|
if(modConfigs.size() != 1) throw new IllegalStateException("#construction.modules != 1. 1 expected");
|
||||||
|
HierarchicalConfiguration modConfig = modConfigs.get(0);
|
||||||
|
String insertionName = modConfig.getString("[@name]");
|
||||||
|
if(insertionName == null) throw new IllegalStateException("insertion[@name] is missing.");
|
||||||
|
String insertionId = modConfig.getString("[@id]");
|
||||||
|
if(insertionId == null) insertionId = "noId";
|
||||||
|
ModKey modKey = makeKey(insertionName,insertionId);
|
||||||
|
AbstractInsertionKey insertionStrategyKey = new AbstractInsertionKey(modKey);
|
||||||
|
AbstractInsertionStrategy insertionStrategy = definedClasses.get(insertionStrategyKey);
|
||||||
|
if(insertionStrategy == null){
|
||||||
|
List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
|
||||||
|
insertionStrategy = createInsertionStrategy(modConfig, vrp, vehicleFleetManager, activityStates, prioListeners);
|
||||||
|
algorithmListeners.addAll(prioListeners);
|
||||||
|
definedClasses.put(insertionStrategyKey,insertionStrategy);
|
||||||
|
}
|
||||||
|
final AbstractInsertionStrategy finalInsertionStrategy = insertionStrategy;
|
||||||
|
|
||||||
|
return new AlgorithmStartsListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
|
||||||
|
CreateInitialSolution createInitialSolution = new CreateInitialSolution(finalInsertionStrategy);
|
||||||
|
createInitialSolution.setGenerateAsMuchAsRoutesAsVehiclesExist(false);
|
||||||
|
VehicleRoutingProblemSolution vrpSol = createInitialSolution.createInitialSolution(vrp);
|
||||||
|
solutions.add(vrpSol);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SolutionSelector getSelector(HierarchicalConfiguration strategyConfig, VehicleRoutingProblem vrp, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedSelectors) {
|
||||||
|
String selectorName = strategyConfig.getString("selector[@name]");
|
||||||
|
if(selectorName == null) throw new IllegalStateException("no solutionSelector defined. define either \"selectRandom\" or \"selectBest\"");
|
||||||
|
String selectorId = strategyConfig.getString("selector[@id]");
|
||||||
|
if(selectorId == null) selectorId="noId";
|
||||||
|
ModKey modKey = makeKey(selectorName,selectorId);
|
||||||
|
SelectorKey selectorKey = new SelectorKey(modKey);
|
||||||
|
SolutionSelector definedSelector = definedSelectors.get(selectorKey);
|
||||||
|
if(definedSelector != null) {
|
||||||
|
return definedSelector;
|
||||||
|
}
|
||||||
|
if(selectorName.equals("selectRandom")){
|
||||||
|
SelectRandomly selector = SelectRandomly.getInstance();
|
||||||
|
definedSelectors.put(selectorKey, selector);
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if(selectorName.equals("selectBest")){
|
||||||
|
SelectBest selector = SelectBest.getInstance();
|
||||||
|
definedSelectors.put(selectorKey, selector);
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("solutionSelector is not know. Currently, it only knows \"selectRandom\" and \"selectBest\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ModKey makeKey(String name, String id){
|
||||||
|
return new ModKey(name, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SolutionAcceptor getAcceptor(HierarchicalConfiguration strategyConfig, VehicleRoutingProblem vrp, Set<PrioritizedVRAListener> algorithmListeners, TypedMap typedMap, int solutionMemory) {
|
||||||
|
String acceptorName = strategyConfig.getString("acceptor[@name]");
|
||||||
|
if(acceptorName == null) throw new IllegalStateException("no solution acceptor is defined");
|
||||||
|
String acceptorId = strategyConfig.getString("acceptor[@id]");
|
||||||
|
if(acceptorId == null) acceptorId = "noId";
|
||||||
|
AcceptorKey acceptorKey = new AcceptorKey(makeKey(acceptorName,acceptorId));
|
||||||
|
SolutionAcceptor definedAcceptor = typedMap.get(acceptorKey);
|
||||||
|
if(definedAcceptor != null) return definedAcceptor;
|
||||||
|
if(acceptorName.equals("acceptNewRemoveWorst")){
|
||||||
|
AcceptNewIfBetterThanWorst acceptor = new AcceptNewIfBetterThanWorst(solutionMemory);
|
||||||
|
typedMap.put(acceptorKey, acceptor);
|
||||||
|
return acceptor;
|
||||||
|
}
|
||||||
|
if(acceptorName.equals("acceptNewRemoveFirst")){
|
||||||
|
AcceptNewRemoveFirst acceptor = new AcceptNewRemoveFirst(solutionMemory);
|
||||||
|
typedMap.put(acceptorKey, acceptor);
|
||||||
|
return acceptor;
|
||||||
|
}
|
||||||
|
if(acceptorName.equals("schrimpfAcceptance")){
|
||||||
|
int iterOfSchrimpf = strategyConfig.getInt("acceptor.warmup");
|
||||||
|
double alpha = strategyConfig.getDouble("acceptor.alpha");
|
||||||
|
SchrimpfAcceptance schrimpf = new SchrimpfAcceptance(solutionMemory, alpha, iterOfSchrimpf);
|
||||||
|
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, schrimpf));
|
||||||
|
typedMap.put(acceptorKey, schrimpf);
|
||||||
|
return schrimpf;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
throw new IllegalStateException("solution acceptor " + acceptorName + " is not known");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SearchStrategyModule buildModule(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager,
|
||||||
|
RouteStates activityStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses) {
|
||||||
|
String moduleName = moduleConfig.getString("[@name]");
|
||||||
|
if(moduleName == null) throw new IllegalStateException("module(-name) is missing.");
|
||||||
|
String moduleId = moduleConfig.getString("[@id]");
|
||||||
|
if(moduleId == null) moduleId = "noId";
|
||||||
|
ModKey modKey = makeKey(moduleName,moduleId);
|
||||||
|
StrategyModuleKey strategyModuleKey = new StrategyModuleKey(modKey);
|
||||||
|
SearchStrategyModule definedModule = definedClasses.get(strategyModuleKey);
|
||||||
|
if(definedModule != null) return definedModule;
|
||||||
|
if(moduleName.equals("ruin_and_recreate")){
|
||||||
|
String ruin_name = moduleConfig.getString("ruin[@name]");
|
||||||
|
if(ruin_name == null) throw new IllegalStateException("module.ruin[@name] is missing.");
|
||||||
|
String ruin_id = moduleConfig.getString("ruin[@id]");
|
||||||
|
if(ruin_id == null) ruin_id = "noId";
|
||||||
|
String shareToRuinString = moduleConfig.getString("ruin.share");
|
||||||
|
if(shareToRuinString == null) throw new IllegalStateException("module.ruin.share is missing.");
|
||||||
|
double shareToRuin = Double.valueOf(shareToRuinString);
|
||||||
|
final RuinStrategy ruin;
|
||||||
|
ModKey ruinKey = makeKey(ruin_name,ruin_id);
|
||||||
|
if(ruin_name.equals("randomRuin")){
|
||||||
|
ruin = getRandomRuin(vrp, activityStates, definedClasses, ruinKey, shareToRuin);
|
||||||
|
}
|
||||||
|
else if(ruin_name.equals("radialRuin")){
|
||||||
|
ruin = getRadialRuin(vrp, activityStates, definedClasses, ruinKey, shareToRuin);
|
||||||
|
}
|
||||||
|
else throw new IllegalStateException("ruin[@name] " + ruin_name + " is not known. Use either randomRuin or radialRuin.");
|
||||||
|
|
||||||
|
String insertionName = moduleConfig.getString("insertion[@name]");
|
||||||
|
if(insertionName == null) throw new IllegalStateException("module.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\"");
|
||||||
|
String insertionId = moduleConfig.getString("insertion[@id]");
|
||||||
|
if(insertionId == null) insertionId = "noId";
|
||||||
|
ModKey insertionKey = makeKey(insertionName,insertionId);
|
||||||
|
AbstractInsertionKey insertionStrategyKey = new AbstractInsertionKey(insertionKey);
|
||||||
|
AbstractInsertionStrategy insertion = definedClasses.get(insertionStrategyKey);
|
||||||
|
if(insertion == null){
|
||||||
|
List<HierarchicalConfiguration> insertionConfigs = moduleConfig.configurationsAt("insertion");
|
||||||
|
if(insertionConfigs.size() != 1) throw new IllegalStateException("this should be 1");
|
||||||
|
List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
|
||||||
|
insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, activityStates, prioListeners);
|
||||||
|
algorithmListeners.addAll(prioListeners);
|
||||||
|
}
|
||||||
|
final AbstractInsertionStrategy final_insertion = insertion;
|
||||||
|
SearchStrategyModule module = new SearchStrategyModule() {
|
||||||
|
|
||||||
|
private Logger logger = Logger.getLogger(SearchStrategyModule.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
|
||||||
|
Collection<Job> ruinedJobs = ruin.ruin(vrpSolution.getRoutes());
|
||||||
|
final_insertion.run(vrpSolution.getRoutes(), ruinedJobs, Double.MAX_VALUE);
|
||||||
|
double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes());
|
||||||
|
vrpSolution.setCost(totalCost);
|
||||||
|
return vrpSolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "[name=ruin_and_recreate][ruin="+ruin+"][recreate="+final_insertion+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addModuleListener(SearchStrategyModuleListener moduleListener) {
|
||||||
|
if(moduleListener instanceof InsertionListener){
|
||||||
|
InsertionListener iListener = (InsertionListener) moduleListener;
|
||||||
|
if(!final_insertion.getListener().contains(iListener)){
|
||||||
|
logger.info("register moduleListener " + moduleListener);
|
||||||
|
final_insertion.addListener(iListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
if(moduleName.equals("bestInsertion") || moduleName.equals("regretInsertion")){
|
||||||
|
List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
|
||||||
|
AbstractInsertionStrategy insertion = getInsertionStrategy(moduleConfig, vrp, vehicleFleetManager, activityStates,
|
||||||
|
definedClasses, modKey, prioListeners);
|
||||||
|
SearchStrategyModule module = getModule(moduleName, insertion, vrp);
|
||||||
|
definedClasses.put(strategyModuleKey, module);
|
||||||
|
algorithmListeners.addAll(prioListeners);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
// if(moduleName.equals("regretInsertion")){
|
||||||
|
// List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
|
||||||
|
// AbstractInsertionKey insertionKey = new AbstractInsertionKey(modKey);
|
||||||
|
// AbstractInsertionStrategy regretInsertion = definedClasses.get(insertionKey);
|
||||||
|
// if(regretInsertion == null){
|
||||||
|
// regretInsertion = createInsertionStrategy(moduleConfig,vrp,vehicleFleetManager,activityStates,prioListeners);
|
||||||
|
// }
|
||||||
|
// SearchStrategyModule module = getModule(moduleName, regretInsertion, vrp);
|
||||||
|
// definedClasses.put(strategyModuleKey, module);
|
||||||
|
// algorithmListeners.addAll(prioListeners);
|
||||||
|
// return module;
|
||||||
|
// }
|
||||||
|
if(moduleName.equals("randomRuin")){
|
||||||
|
double shareToRuin = moduleConfig.getDouble("share");
|
||||||
|
RuinStrategy ruin = getRandomRuin(vrp, activityStates,definedClasses, modKey, shareToRuin);
|
||||||
|
SearchStrategyModule module = getModule(moduleName, ruin);
|
||||||
|
definedClasses.put(strategyModuleKey, module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
if(moduleName.equals("radialRuin")){
|
||||||
|
double shareToRuin = moduleConfig.getDouble("share");
|
||||||
|
RuinStrategy ruin = getRadialRuin(vrp, activityStates,definedClasses, modKey, shareToRuin);
|
||||||
|
SearchStrategyModule module = getModule(moduleName, ruin);
|
||||||
|
definedClasses.put(strategyModuleKey, module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
if(moduleName.equals("gendreauPostOpt")){
|
||||||
|
int iterations = moduleConfig.getInt("iterations");
|
||||||
|
double share = moduleConfig.getDouble("share");
|
||||||
|
String ruinName = moduleConfig.getString("ruin[@name]");
|
||||||
|
if(ruinName == null) throw new IllegalStateException("gendreauPostOpt.ruin[@name] is missing. set it to \"radialRuin\" or \"randomRuin\"");
|
||||||
|
String ruinId = moduleConfig.getString("ruin[@id]");
|
||||||
|
if(ruinId == null) ruinId = "noId";
|
||||||
|
ModKey ruinKey = makeKey(ruinName,ruinId);
|
||||||
|
RuinStrategyKey stratKey = new RuinStrategyKey(ruinKey);
|
||||||
|
RuinStrategy ruin = definedClasses.get(stratKey);
|
||||||
|
if(ruin == null){
|
||||||
|
ruin = RuinRadial.newInstance(vrp, 0.3, new JobDistanceAvgCosts(vrp.getTransportCosts()), new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts()));
|
||||||
|
definedClasses.put(stratKey, ruin);
|
||||||
|
}
|
||||||
|
|
||||||
|
String insertionName = moduleConfig.getString("insertion[@name]");
|
||||||
|
if(insertionName == null) throw new IllegalStateException("gendreauPostOpt.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\"");
|
||||||
|
String insertionId = moduleConfig.getString("insertion[@id]");
|
||||||
|
if(insertionId == null) insertionId = "noId";
|
||||||
|
ModKey insertionKey = makeKey(insertionName,insertionId);
|
||||||
|
AbstractInsertionKey insertionStrategyKey = new AbstractInsertionKey(insertionKey);
|
||||||
|
AbstractInsertionStrategy insertion = definedClasses.get(insertionStrategyKey);
|
||||||
|
if(insertion == null){
|
||||||
|
List<HierarchicalConfiguration> insertionConfigs = moduleConfig.configurationsAt("insertion");
|
||||||
|
if(insertionConfigs.size() != 1) throw new IllegalStateException("this should be 1");
|
||||||
|
List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
|
||||||
|
insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, activityStates, prioListeners);
|
||||||
|
algorithmListeners.addAll(prioListeners);
|
||||||
|
}
|
||||||
|
GendreauPostOpt postOpt = new GendreauPostOpt(vrp, ruin, insertion);
|
||||||
|
postOpt.setShareOfJobsToRuin(share);
|
||||||
|
postOpt.setNuOfIterations(iterations);
|
||||||
|
postOpt.setFleetManager(vehicleFleetManager);
|
||||||
|
definedClasses.put(strategyModuleKey, postOpt);
|
||||||
|
return postOpt;
|
||||||
|
}
|
||||||
|
throw new NullPointerException("no module found with moduleName=" + moduleName +
|
||||||
|
"\n\tcheck config whether the correct names are used" +
|
||||||
|
"\n\tcurrently there are following modules available: " +
|
||||||
|
"\n\tbestInsertion" +
|
||||||
|
"\n\trandomRuin" +
|
||||||
|
"\n\tradialRuin" +
|
||||||
|
"\n\tgendreauPostOpt");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AbstractInsertionStrategy getInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp,VehicleFleetManager vehicleFleetManager,
|
||||||
|
RouteStates activityStates, TypedMap definedClasses,
|
||||||
|
ModKey modKey, List<PrioritizedVRAListener> prioListeners) {
|
||||||
|
AbstractInsertionKey insertionKey = new AbstractInsertionKey(modKey);
|
||||||
|
AbstractInsertionStrategy bestInsertion = definedClasses.get(insertionKey);
|
||||||
|
if(bestInsertion == null){
|
||||||
|
bestInsertion = createInsertionStrategy(moduleConfig,vrp,vehicleFleetManager,activityStates,prioListeners);
|
||||||
|
}
|
||||||
|
return bestInsertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RuinStrategy getRadialRuin(VehicleRoutingProblem vrp,
|
||||||
|
RouteStates activityStates, TypedMap definedClasses,
|
||||||
|
ModKey modKey, double shareToRuin) {
|
||||||
|
RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
|
||||||
|
RuinStrategy ruin = definedClasses.get(stratKey);
|
||||||
|
if(ruin == null){
|
||||||
|
ruin = RuinRadial.newInstance(vrp, shareToRuin, new JobDistanceAvgCosts(vrp.getTransportCosts()), new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts()));
|
||||||
|
definedClasses.put(stratKey, ruin);
|
||||||
|
}
|
||||||
|
return ruin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RuinStrategy getRandomRuin(VehicleRoutingProblem vrp,
|
||||||
|
RouteStates activityStates, TypedMap definedClasses,
|
||||||
|
ModKey modKey, double shareToRuin) {
|
||||||
|
RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
|
||||||
|
RuinStrategy ruin = definedClasses.get(stratKey);
|
||||||
|
if(ruin == null){
|
||||||
|
ruin = RuinRandom.newInstance(vrp, shareToRuin, new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts()));
|
||||||
|
definedClasses.put(stratKey, ruin);
|
||||||
|
}
|
||||||
|
return ruin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AbstractInsertionStrategy createInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp,VehicleFleetManager vehicleFleetManager, RouteStates activityStates, List<PrioritizedVRAListener> algorithmListeners) {
|
||||||
|
AbstractInsertionStrategy insertion = InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, activityStates, algorithmListeners);
|
||||||
|
return insertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SearchStrategyModule getModule(final String moduleName, final AbstractInsertionStrategy insertion, final VehicleRoutingProblem vrp){
|
||||||
|
|
||||||
|
return new SearchStrategyModule() {
|
||||||
|
|
||||||
|
private Logger logger = Logger.getLogger(SearchStrategyModule.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
|
||||||
|
List<Job> unassignedJobs = getUnassignedJobs(vrpSolution,vrp);
|
||||||
|
// logger.info("unassigned: " + unassignedJobs.size());
|
||||||
|
insertion.run(vrpSolution.getRoutes(), unassignedJobs, Double.MAX_VALUE);
|
||||||
|
int jobsInSolution = countJobs(vrpSolution);
|
||||||
|
double penalty = 0.0;
|
||||||
|
if(jobsInSolution != vrp.getJobs().values().size()){
|
||||||
|
throw new IllegalStateException("solution not valid\n" + "#jobsInSolution=" + jobsInSolution + " #jobsInVrp=" + vrp.getJobs().values().size());
|
||||||
|
// logger.warn("solution not valid\n" + "#jobsInSolution=" + jobsInSolution + " #jobsInVrp=" + vrp.getJobs().values().size());
|
||||||
|
//// throw new IllegalStateException("solution not valid\n" +
|
||||||
|
//// "#jobsInSolution=" + jobsInSolution + " #jobsInVrp=" + vrp.getJobs().values().size());
|
||||||
|
// logger.warn("a penalty of 1000 is added for each unassigned customer");
|
||||||
|
// penalty = (vrp.getJobs().values().size() - jobsInSolution)*1000.0;
|
||||||
|
// logger.warn("penalty = " + penalty);
|
||||||
|
}
|
||||||
|
double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes());
|
||||||
|
vrpSolution.setCost(totalCost + penalty);
|
||||||
|
return vrpSolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name="+insertion+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private int countJobs(VehicleRoutingProblemSolution vrpSolution) {
|
||||||
|
int counter = 0;
|
||||||
|
for(VehicleRoute route : vrpSolution.getRoutes()){
|
||||||
|
counter += route.getTourActivities().jobSize();
|
||||||
|
}
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Job> getUnassignedJobs(VehicleRoutingProblemSolution vrpSolution,VehicleRoutingProblem vrp) {
|
||||||
|
List<Job> unassignedJobs = new ArrayList<Job>();
|
||||||
|
for(Job j : vrp.getJobs().values()){
|
||||||
|
boolean notAssigned = true;
|
||||||
|
for(VehicleRoute r : vrpSolution.getRoutes()){
|
||||||
|
if(r.getTourActivities().servesJob(j)){
|
||||||
|
notAssigned = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(notAssigned){
|
||||||
|
unassignedJobs.add(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unassignedJobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addModuleListener(SearchStrategyModuleListener moduleListener) {
|
||||||
|
if(moduleListener instanceof InsertionListener){
|
||||||
|
InsertionListener iListener = (InsertionListener) moduleListener;
|
||||||
|
if(!insertion.getListener().contains(iListener)){
|
||||||
|
logger.info("register moduleListener " + moduleListener);
|
||||||
|
insertion.addListener(iListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SearchStrategyModule getModule(final String moduleName, final RuinStrategy ruin) {
|
||||||
|
|
||||||
|
|
||||||
|
return new SearchStrategyModule() {
|
||||||
|
|
||||||
|
private Logger logger = Logger.getLogger(SearchStrategyModule.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
|
||||||
|
ruin.ruin(vrpSolution.getRoutes());
|
||||||
|
return vrpSolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name="+ruin+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addModuleListener(SearchStrategyModuleListener moduleListener) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
40
jsprit-core/src/main/java/algorithms/VehicleSwitched.java
Normal file
40
jsprit-core/src/main/java/algorithms/VehicleSwitched.java
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import algorithms.RouteAlgorithm.VehicleSwitchedListener;
|
||||||
|
|
||||||
|
class VehicleSwitched implements VehicleSwitchedListener{
|
||||||
|
|
||||||
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
|
VehicleSwitched(VehicleFleetManager fleetManager){
|
||||||
|
this.fleetManager = fleetManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle) {
|
||||||
|
fleetManager.unlock(oldVehicle);
|
||||||
|
fleetManager.lock(newVehicle);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms.acceptors;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
public class AcceptNewIfBetterThanWorst implements SolutionAcceptor{
|
||||||
|
|
||||||
|
private final int solutionMemory;
|
||||||
|
|
||||||
|
public AcceptNewIfBetterThanWorst(int solutionMemory){
|
||||||
|
this.solutionMemory = solutionMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts every solution if solution memory allows. If memory occupied, than accepts new solution only if better than the worst in memory.
|
||||||
|
* Consequently, the worst solution is removed from solutions, and the new solution added.
|
||||||
|
*
|
||||||
|
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
||||||
|
boolean solutionAccepted = false;
|
||||||
|
if (solutions.size() < solutionMemory) {
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
} else {
|
||||||
|
VehicleRoutingProblemSolution worstSolution = null;
|
||||||
|
for (VehicleRoutingProblemSolution s : solutions) {
|
||||||
|
if (worstSolution == null) worstSolution = s;
|
||||||
|
else if (s.getCost() > worstSolution.getCost()) worstSolution = s;
|
||||||
|
}
|
||||||
|
if(newSolution.getCost() < worstSolution.getCost()){
|
||||||
|
solutions.remove(worstSolution);
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return solutionAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=acceptNewRemoveWorst]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms.acceptors;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
public class AcceptNewRemoveFirst implements SolutionAcceptor{
|
||||||
|
|
||||||
|
private final int solutionMemory;
|
||||||
|
|
||||||
|
public AcceptNewRemoveFirst(int solutionMemory){
|
||||||
|
this.solutionMemory = solutionMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts every solution if solution memory allows. If memory occupied, than accepts new solution only if better than the worst in memory.
|
||||||
|
* Consequently, the worst solution is removed from solutions, and the new solution added.
|
||||||
|
*
|
||||||
|
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
||||||
|
if (solutions.size() >= solutionMemory) {
|
||||||
|
solutions.remove(solutions.iterator().next());
|
||||||
|
}
|
||||||
|
solutions.add(newSolution);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=acceptNewRemoveFirst]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms.acceptors;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.Solutions;
|
||||||
|
import algorithms.VehicleRoutingAlgorithms;
|
||||||
|
import basics.VehicleRoutingAlgorithm;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.AlgorithmStartsListener;
|
||||||
|
import basics.algo.IterationEndsListener;
|
||||||
|
import basics.algo.IterationStartsListener;
|
||||||
|
import basics.io.AlgorithmConfig;
|
||||||
|
import basics.io.AlgorithmConfigXmlReader;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsListener, AlgorithmStartsListener{
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(SchrimpfAcceptance.class);
|
||||||
|
|
||||||
|
private final double alpha;
|
||||||
|
|
||||||
|
private int nOfTotalIterations = 1000;
|
||||||
|
|
||||||
|
private int currentIteration = 0;
|
||||||
|
|
||||||
|
private double initialThreshold = 0.0;
|
||||||
|
|
||||||
|
private final int nOfRandomWalks;
|
||||||
|
|
||||||
|
private final int solutionMemory;
|
||||||
|
|
||||||
|
|
||||||
|
public SchrimpfAcceptance(int solutionMemory, double alpha, int nOfWarmupIterations) {
|
||||||
|
super();
|
||||||
|
this.alpha = alpha;
|
||||||
|
this.nOfRandomWalks = nOfWarmupIterations;
|
||||||
|
this.solutionMemory = solutionMemory;
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
||||||
|
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(newSolution.getCost() < worst.getCost() + threshold){
|
||||||
|
solutions.remove(worst);
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return solutionAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=schrimpfAcceptanceFunction][alpha="+alpha+"][warmup=" + nOfRandomWalks + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getThreshold(int iteration) {
|
||||||
|
double scheduleVariable = (double) iteration / (double) nOfTotalIterations;
|
||||||
|
// logger.debug("iter="+iteration+" totalIter="+nOfTotalIterations+" scheduling="+scheduleVariable);
|
||||||
|
double currentThreshold = initialThreshold * Math.exp(-Math.log(2) * scheduleVariable / alpha);
|
||||||
|
return currentThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
reset();
|
||||||
|
logger.info("---------------------------------------------------------------------");
|
||||||
|
logger.info("prepare schrimpfAcceptanceFunction, i.e. determine initial threshold");
|
||||||
|
logger.info("start random-walk (see algorith-config at scr/main/resources/randomWalk.xml)");
|
||||||
|
double now = System.currentTimeMillis();
|
||||||
|
this.nOfTotalIterations = algorithm.getNuOfIterations();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* randomWalk to determine standardDev
|
||||||
|
*/
|
||||||
|
final double[] results = new double[nOfRandomWalks];
|
||||||
|
|
||||||
|
URL resource = this.getClass().getClassLoader().getResource("randomWalk.xml");
|
||||||
|
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
||||||
|
new AlgorithmConfigXmlReader(algorithmConfig).read(resource.getPath());
|
||||||
|
VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.createAlgorithm(problem, algorithmConfig);
|
||||||
|
vra.setNuOfIterations(nOfRandomWalks);
|
||||||
|
vra.getAlgorithmListeners().addListener(new IterationEndsListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informIterationEnds(int iteration, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
double result = Solutions.getBest(solutions).getCost();
|
||||||
|
// logger.info("result="+result);
|
||||||
|
results[iteration-1] = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
vra.searchSolutions();
|
||||||
|
|
||||||
|
StandardDeviation dev = new StandardDeviation();
|
||||||
|
double standardDeviation = dev.evaluate(results);
|
||||||
|
initialThreshold = standardDeviation / 2;
|
||||||
|
|
||||||
|
logger.info("warmup done");
|
||||||
|
logger.info("total time: " + ((System.currentTimeMillis()-now)/1000.0) + "s");
|
||||||
|
logger.info("initial threshold: " + initialThreshold);
|
||||||
|
logger.info("---------------------------------------------------------------------");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reset() {
|
||||||
|
currentIteration = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
currentIteration = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms.acceptors;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acceptor that decides whether the newSolution is accepted or not.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface SolutionAcceptor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accepts solution or not, and returns true if a new solution has been accepted.
|
||||||
|
*
|
||||||
|
* <p>If the solution is accepted, it is added to solutions, i.e. the solutions-collections is modified.
|
||||||
|
*
|
||||||
|
* @param solutions
|
||||||
|
* @param newSolution
|
||||||
|
* @return TODO
|
||||||
|
*/
|
||||||
|
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms.selectors;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class SelectBest implements SolutionSelector{
|
||||||
|
|
||||||
|
private static SelectBest selector = null;
|
||||||
|
|
||||||
|
public static SelectBest getInstance(){
|
||||||
|
if(selector == null){
|
||||||
|
selector = new SelectBest();
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleRoutingProblemSolution selectSolution(Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
double minCost = Double.MAX_VALUE;
|
||||||
|
VehicleRoutingProblemSolution bestSolution = null;
|
||||||
|
for(VehicleRoutingProblemSolution sol : solutions){
|
||||||
|
if(bestSolution == null){
|
||||||
|
bestSolution = sol;
|
||||||
|
minCost = sol.getCost();
|
||||||
|
}
|
||||||
|
else if(sol.getCost() < minCost){
|
||||||
|
bestSolution = sol;
|
||||||
|
minCost = sol.getCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestSolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=selectBest]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms.selectors;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
import util.RandomNumberGeneration;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class SelectRandomly implements SolutionSelector{
|
||||||
|
|
||||||
|
private static SelectRandomly selector = null;
|
||||||
|
|
||||||
|
public static SelectRandomly getInstance(){
|
||||||
|
if(selector == null){
|
||||||
|
selector = new SelectRandomly();
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Random random = RandomNumberGeneration.getRandom();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleRoutingProblemSolution selectSolution(Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
if(solutions.isEmpty()) return null;
|
||||||
|
List<VehicleRoutingProblemSolution> solList = new ArrayList<VehicleRoutingProblemSolution>(solutions);
|
||||||
|
int randomIndex = random.nextInt(solutions.size());
|
||||||
|
return solList.get(randomIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRandom(Random random) {
|
||||||
|
this.random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms.selectors;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
public interface SolutionSelector {
|
||||||
|
|
||||||
|
public VehicleRoutingProblemSolution selectSolution(Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
|
|
||||||
|
}
|
||||||
22
jsprit-core/src/main/java/basics/Job.java
Normal file
22
jsprit-core/src/main/java/basics/Job.java
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics;
|
||||||
|
|
||||||
|
public interface Job {
|
||||||
|
|
||||||
|
public String getId();
|
||||||
|
|
||||||
|
public int getCapacityDemand();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
183
jsprit-core/src/main/java/basics/Service.java
Normal file
183
jsprit-core/src/main/java/basics/Service.java
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics;
|
||||||
|
|
||||||
|
import basics.route.TimeWindow;
|
||||||
|
import util.Coordinate;
|
||||||
|
|
||||||
|
|
||||||
|
public class Service implements Job {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
public static Builder newInstance(String id, int size){
|
||||||
|
return new Builder(id,size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String locationId;
|
||||||
|
private String name = "service";
|
||||||
|
private Coordinate coord;
|
||||||
|
private double serviceTime;
|
||||||
|
private TimeWindow timeWindow = TimeWindow.newInstance(0.0, Double.MAX_VALUE);
|
||||||
|
private int demand;
|
||||||
|
|
||||||
|
private Builder(String id, int size) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
this.demand = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setName(String name){
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setLocationId(String locationId){
|
||||||
|
this.locationId = locationId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setCoord(Coordinate coord){
|
||||||
|
this.coord = coord;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setServiceTime(double serviceTime){
|
||||||
|
this.serviceTime = serviceTime;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setTimeWindow(TimeWindow tw){
|
||||||
|
this.timeWindow = tw;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Service build(){
|
||||||
|
if(locationId == null) {
|
||||||
|
if(coord == null) throw new IllegalStateException("either locationId or a coordinate must be given. But is not.");
|
||||||
|
locationId = coord.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Service(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
private final String locationId;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final Coordinate coord;
|
||||||
|
|
||||||
|
private final double serviceTime;
|
||||||
|
|
||||||
|
private final TimeWindow timeWindow;
|
||||||
|
|
||||||
|
private final int demand;
|
||||||
|
|
||||||
|
private Service(Builder builder){
|
||||||
|
id = builder.id;
|
||||||
|
locationId = builder.locationId;
|
||||||
|
coord = builder.coord;
|
||||||
|
serviceTime = builder.serviceTime;
|
||||||
|
timeWindow = builder.timeWindow;
|
||||||
|
demand = builder.demand;
|
||||||
|
name = builder.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocationId() {
|
||||||
|
return locationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Coordinate getCoord(){
|
||||||
|
return coord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getServiceDuration() {
|
||||||
|
return serviceTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeWindow getTimeWindow(){
|
||||||
|
return timeWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCapacityDemand() {
|
||||||
|
return demand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
public String getType() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[id=" + id + "][locationId=" + locationId + "][coord="+coord+"][size=" + demand + "][serviceTime=" + serviceTime + "][timeWindow=" + timeWindow + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
Service other = (Service) obj;
|
||||||
|
if (id == null) {
|
||||||
|
if (other.id != null)
|
||||||
|
return false;
|
||||||
|
} else if (!id.equals(other.id))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
202
jsprit-core/src/main/java/basics/VehicleRoutingAlgorithm.java
Normal file
202
jsprit-core/src/main/java/basics/VehicleRoutingAlgorithm.java
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.Counter;
|
||||||
|
import algorithms.acceptors.SolutionAcceptor;
|
||||||
|
import basics.algo.AlgorithmEndsListener;
|
||||||
|
import basics.algo.AlgorithmStartsListener;
|
||||||
|
import basics.algo.IterationEndsListener;
|
||||||
|
import basics.algo.IterationStartsListener;
|
||||||
|
import basics.algo.SearchStrategy;
|
||||||
|
import basics.algo.SearchStrategyManager;
|
||||||
|
import basics.algo.VehicleRoutingAlgorithmListener;
|
||||||
|
import basics.algo.VehicleRoutingAlgorithmListeners;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Algorithm that solves a {@link VehicleRoutingProblem}.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class VehicleRoutingAlgorithm {
|
||||||
|
|
||||||
|
public static final int NOBREAK = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(VehicleRoutingAlgorithm.class);
|
||||||
|
|
||||||
|
private VehicleRoutingProblem problem;
|
||||||
|
|
||||||
|
private int nOfIterations = 100;
|
||||||
|
|
||||||
|
private int prematureBreak = NOBREAK;
|
||||||
|
|
||||||
|
private Counter counter = new Counter("iterations ");
|
||||||
|
|
||||||
|
private SearchStrategyManager searchStrategyManager;
|
||||||
|
|
||||||
|
private VehicleRoutingAlgorithmListeners algoListeners = new VehicleRoutingAlgorithmListeners();
|
||||||
|
|
||||||
|
private Collection<VehicleRoutingProblemSolution> initialSolutions;
|
||||||
|
|
||||||
|
public VehicleRoutingAlgorithm(VehicleRoutingProblem problem, SearchStrategyManager searchStrategyManager) {
|
||||||
|
super();
|
||||||
|
this.problem = problem;
|
||||||
|
this.searchStrategyManager = searchStrategyManager;
|
||||||
|
initialSolutions = new ArrayList<VehicleRoutingProblemSolution>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoutingAlgorithm(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> initialSolutions, SearchStrategyManager searchStrategyManager) {
|
||||||
|
super();
|
||||||
|
this.problem = problem;
|
||||||
|
this.searchStrategyManager = searchStrategyManager;
|
||||||
|
this.initialSolutions = initialSolutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds solution to the collection of initial solutions.
|
||||||
|
*
|
||||||
|
* @param solution
|
||||||
|
*/
|
||||||
|
public void addInitialSolution(VehicleRoutingProblemSolution solution){
|
||||||
|
initialSolutions.add(solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets premature break.
|
||||||
|
*
|
||||||
|
* <p>This breaks the algorithm prematurely after the assigned number of iterations without improvement (see input parameter).
|
||||||
|
* Improvement is what {@link SolutionAcceptor} understands about improvement. Or to put it in other words, the algo breaks prematurely after
|
||||||
|
* the assigned number of iterations without solution-acceptance.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param iterationsWithoutImprovement
|
||||||
|
*/
|
||||||
|
public void setPrematureBreak(int iterationsWithoutImprovement){
|
||||||
|
prematureBreak = iterationsWithoutImprovement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link SearchStrategyManager}.
|
||||||
|
*
|
||||||
|
* @return SearchStrategyManager
|
||||||
|
*/
|
||||||
|
public SearchStrategyManager getSearchStrategyManager() {
|
||||||
|
return searchStrategyManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the vehicle routing algorithm and returns a number of generated solutions.
|
||||||
|
*
|
||||||
|
* <p>The algorithm runs as long as it is specified in nuOfIterations and prematureBreak. In each iteration it selects a searchStrategy according
|
||||||
|
* to searchStrategyManager and runs the strategy to improve solutions.
|
||||||
|
* <p>Note that clients are allowed to observe/listen the algorithm. See {@link VehicleRoutingAlgorithmListener} and its according listeners.
|
||||||
|
*
|
||||||
|
* @return Collection<VehicleRoutingProblemSolution> the solutions
|
||||||
|
* @see {@link SearchStrategyManager}, {@link VehicleRoutingAlgorithmListener}, {@link AlgorithmStartsListener}, {@link AlgorithmEndsListener}, {@link IterationStartsListener}, {@link IterationEndsListener}
|
||||||
|
*/
|
||||||
|
public Collection<VehicleRoutingProblemSolution> searchSolutions(){
|
||||||
|
logger.info("------------------------------------------------");
|
||||||
|
logger.info("algorithm starts");
|
||||||
|
double now = System.currentTimeMillis();
|
||||||
|
verify();
|
||||||
|
counter.reset();
|
||||||
|
Collection<VehicleRoutingProblemSolution> solutions = new ArrayList<VehicleRoutingProblemSolution>(initialSolutions);
|
||||||
|
algorithmStarts(problem,solutions);
|
||||||
|
int iterWithoutImprovement = 0;
|
||||||
|
logger.info("iterations start");
|
||||||
|
for(int i=0;i<nOfIterations;i++){
|
||||||
|
iterationStarts(i+1,problem,solutions);
|
||||||
|
counter.incCounter();
|
||||||
|
SearchStrategy strat = searchStrategyManager.getRandomStrategy();
|
||||||
|
boolean newSolutionFoundAndAccepted = strat.run(problem, solutions);
|
||||||
|
selectedStrategy(strat.getName(),problem, solutions);
|
||||||
|
if(newSolutionFoundAndAccepted) iterWithoutImprovement = 0;
|
||||||
|
else iterWithoutImprovement++;
|
||||||
|
if(iterWithoutImprovement > prematureBreak){
|
||||||
|
logger.info("premature break at iteration "+ (i+1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iterationEnds(i+1,problem,solutions);
|
||||||
|
}
|
||||||
|
logger.info("iterations end at " + nOfIterations + " iterations");
|
||||||
|
algorithmEnds(problem,solutions);
|
||||||
|
logger.info("total time: " + ((System.currentTimeMillis()-now)/1000.0) + "s");
|
||||||
|
logger.info("done");
|
||||||
|
logger.info("------------------------------------------------");
|
||||||
|
return solutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void selectedStrategy(String name, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
algoListeners.selectedStrategy(name,problem, solutions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of iterations.
|
||||||
|
*
|
||||||
|
* @return iterations
|
||||||
|
*/
|
||||||
|
public int getNuOfIterations(){
|
||||||
|
return nOfIterations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asserts that the sum of probabilities of the searchStrategies is equal to 1.0.
|
||||||
|
*/
|
||||||
|
private void verify() {
|
||||||
|
double sum = 0.0;
|
||||||
|
for(Double prob : searchStrategyManager.getProbabilities()){
|
||||||
|
sum += prob;
|
||||||
|
}
|
||||||
|
if(sum < 1.0*0.99 || sum > 1.0*1.01) throw new IllegalStateException("sum of probabilities is not 1.0, but is "+ sum + ". make sure that the sum of the probability of each searchStrategy is 1.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void algorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
algoListeners.algorithmEnds(problem, solutions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoutingAlgorithmListeners getAlgorithmListeners() {
|
||||||
|
return algoListeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
algoListeners.iterationEnds(i,problem, solutions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void iterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
algoListeners.iterationStarts(i, problem, solutions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void algorithmStarts(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
algoListeners.algorithmStarts(problem, this, solutions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNuOfIterations(int nOfIterations) {
|
||||||
|
this.nOfIterations = nOfIterations;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
473
jsprit-core/src/main/java/basics/VehicleRoutingProblem.java
Normal file
473
jsprit-core/src/main/java/basics/VehicleRoutingProblem.java
Normal file
|
|
@ -0,0 +1,473 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
|
*
|
||||||
|
* All rights reserved. This program and the accompanying materials
|
||||||
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
|
* which accompanies this distribution, and is available at
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.Coordinate;
|
||||||
|
import util.CrowFlyCosts;
|
||||||
|
import util.Locations;
|
||||||
|
import util.Neighborhood;
|
||||||
|
import util.NeighborhoodImpl;
|
||||||
|
import basics.costs.DefaultVehicleRoutingActivityCosts;
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleImpl;
|
||||||
|
import basics.route.VehicleImpl.VehicleType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains and describes the vehicle routing problem.
|
||||||
|
*
|
||||||
|
* <p>A routing problem is defined as jobs, vehicles and costs.
|
||||||
|
*
|
||||||
|
* <p> To construct the problem, use VehicleRoutingProblem.Builder (VehicleRoutingProblem.Builder.newInstance()).
|
||||||
|
*
|
||||||
|
* <p>By default, fleetSize is INFINITE and fleetComposition is HOMOGENEOUS, transport-costs are calculated as euclidean-distance (CrowFlyCosts),
|
||||||
|
* and activity-costs are set to DefaultVehicleRoutingActivityCosts which represent hard time-windows (missed time-windows are penalyzed with Double.MAX_VALUE).
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class VehicleRoutingProblem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder to build the routing-problem.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new instance of this builder.
|
||||||
|
*
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public static Builder newInstance(){ return new Builder(); }
|
||||||
|
|
||||||
|
private VehicleRoutingTransportCosts transportCosts;
|
||||||
|
|
||||||
|
private VehicleRoutingActivityCosts activityCosts = new DefaultVehicleRoutingActivityCosts();
|
||||||
|
|
||||||
|
private Map<String,Job> jobs;
|
||||||
|
|
||||||
|
private Collection<Vehicle> vehicles;
|
||||||
|
|
||||||
|
private Map<String, Coordinate> coordinates;
|
||||||
|
|
||||||
|
private FleetSize fleetSize = FleetSize.INFINITE;
|
||||||
|
|
||||||
|
private FleetComposition fleetComposition = FleetComposition.HOMOGENEOUS;
|
||||||
|
|
||||||
|
private Collection<VehicleType> vehicleTypes;
|
||||||
|
|
||||||
|
public Builder() {
|
||||||
|
jobs = new HashMap<String, Job>();
|
||||||
|
vehicles = new ArrayList<Vehicle>();
|
||||||
|
coordinates = new HashMap<String, Coordinate>();
|
||||||
|
vehicleTypes = new ArrayList<VehicleImpl.VehicleType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a location (i.e. coordinate) and returns the key of the location which is Coordinate.toString().
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @return locationId
|
||||||
|
* @see Coordinate
|
||||||
|
*/
|
||||||
|
public String createLocation(double x, double y){
|
||||||
|
Coordinate coord = new Coordinate(x, y);
|
||||||
|
String id = coord.toString();
|
||||||
|
if(!coordinates.containsKey(id)){
|
||||||
|
coordinates.put(id, coord);
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unmodifiable map of locations (mapped by their id).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Map<String,Coordinate> getLocationMap(){
|
||||||
|
return Collections.unmodifiableMap(coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the locations collected by this builder.
|
||||||
|
*
|
||||||
|
* <p>Locations are cached when adding a shipment, service, depot, vehicle.
|
||||||
|
*
|
||||||
|
* @return locations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public Locations getLocations(){
|
||||||
|
return new Locations() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Coordinate getCoord(String id) {
|
||||||
|
return coordinates.get(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets routing costs.
|
||||||
|
*
|
||||||
|
* @param costs
|
||||||
|
* @return builder
|
||||||
|
* @see VehicleRoutingTransportCosts
|
||||||
|
*/
|
||||||
|
public Builder setRoutingCost(VehicleRoutingTransportCosts costs){
|
||||||
|
this.transportCosts = costs;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the type of fleetSize.
|
||||||
|
*
|
||||||
|
* <p>FleetSize is either FleetSize.INFINITE or FleetSize.FINITE
|
||||||
|
*
|
||||||
|
* @param fleetSize
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Builder setFleetSize(FleetSize fleetSize){
|
||||||
|
this.fleetSize = fleetSize;
|
||||||
|
// if(fleetSize.equals(FleetSize.INFINITE)){
|
||||||
|
// fleetSizeIsInfinite=true;
|
||||||
|
// }
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the fleetComposition.
|
||||||
|
*
|
||||||
|
* <p>FleetComposition is either FleetComposition.HETEROGENEOUS or FleetComposition.HOMOGENEOUS
|
||||||
|
*
|
||||||
|
* @param fleetComposition
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Builder setFleetComposition(FleetComposition fleetComposition){
|
||||||
|
this.fleetComposition = fleetComposition;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a service to jobList.
|
||||||
|
*
|
||||||
|
* <p>If jobList already contains service, a warning message is printed, and the existing job will be overwritten.
|
||||||
|
*
|
||||||
|
* @param service
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Builder addService(Service service){
|
||||||
|
coordinates.put(service.getLocationId(), service.getCoord());
|
||||||
|
if(jobs.containsKey(service.getId())){ logger.warn("service " + service + " already in job list. overrides existing job."); }
|
||||||
|
jobs.put(service.getId(),service);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a job which is either a service or a shipment.
|
||||||
|
*
|
||||||
|
* @param job
|
||||||
|
* @return
|
||||||
|
* @throws IllegalStateException if job is neither a shipment or a service.
|
||||||
|
*/
|
||||||
|
public Builder addJob(Job job) {
|
||||||
|
if(job instanceof Service) {
|
||||||
|
addService((Service) job);
|
||||||
|
}
|
||||||
|
// else if(job instanceof Shipment){
|
||||||
|
// addShipment((Shipment)job);
|
||||||
|
// }
|
||||||
|
else throw new IllegalStateException("job can only be a shipment or a service, but is instance of " + job.getClass());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private void addShipment(Shipment job) {
|
||||||
|
// coordinates.put(job.getFromId(),job.getFromCoord());
|
||||||
|
// coordinates.put(job.getToId(), job.getToCoord());
|
||||||
|
// if(jobs.containsKey(job.getId())){ logger.warn("service " + job + " already in job list. overrides existing job."); }
|
||||||
|
// jobs.put(job.getId(),job);
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a vehicle.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param vehicle
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Builder addVehicle(Vehicle vehicle) {
|
||||||
|
// fleetSizeIsFinite = true;
|
||||||
|
vehicles.add(vehicle);
|
||||||
|
if(!vehicleTypes.contains(vehicle.getType())){
|
||||||
|
vehicleTypes.add(vehicle.getType());
|
||||||
|
}
|
||||||
|
coordinates.put(vehicle.getLocationId(), vehicle.getCoord());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a vehicleType.
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder addVehicleType(VehicleType type){
|
||||||
|
vehicleTypes.add(type);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the activityCostFunction that considers also activities on a vehicle-route.
|
||||||
|
*
|
||||||
|
* <p>Here you can consider missed time-windows for example. By default, this is set to a DefaultVehicleActivityCostFunction.
|
||||||
|
*
|
||||||
|
* @param activityCosts
|
||||||
|
* @return
|
||||||
|
* @see VehicleRoutingTransportCosts, DefaultVehicleRouteCostFunction
|
||||||
|
*/
|
||||||
|
public Builder setActivityCosts(VehicleRoutingActivityCosts activityCosts){
|
||||||
|
this.activityCosts = activityCosts;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoutingProblem build() {
|
||||||
|
log.info("build problem ...");
|
||||||
|
if(transportCosts == null){
|
||||||
|
logger.warn("set routing costs crowFlyDistance.");
|
||||||
|
transportCosts = new CrowFlyCosts(getLocations());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new VehicleRoutingProblem(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addLocation(String id, Coordinate coord) {
|
||||||
|
coordinates.put(id, coord);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addAllJobs(Collection<Job> jobs) {
|
||||||
|
for(Job j : jobs){
|
||||||
|
addJob(j);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addAllVehicles(Collection<Vehicle> vehicles) {
|
||||||
|
for(Vehicle v : vehicles){
|
||||||
|
addVehicle(v);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum that characterizes the fleet-size.
|
||||||
|
*
|
||||||
|
* @author sschroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static enum FleetSize {
|
||||||
|
FINITE, INFINITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum that characterizes fleet-compostion.
|
||||||
|
*
|
||||||
|
* @author sschroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static enum FleetComposition {
|
||||||
|
HETEROGENEOUS, HOMOGENEOUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder newBuilderInstance(){
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Logger log = Logger.getLogger(VehicleRoutingProblem.class);
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(VehicleRoutingProblem.class);
|
||||||
|
|
||||||
|
private VehicleRoutingTransportCosts transportCosts;
|
||||||
|
|
||||||
|
private VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
private Neighborhood neighborhood;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the neighborhood
|
||||||
|
*/
|
||||||
|
public Neighborhood getNeighborhood() {
|
||||||
|
return neighborhood;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param neighborhood the neighborhood to set
|
||||||
|
*/
|
||||||
|
public void setNeighborhood(Neighborhood neighborhood) {
|
||||||
|
this.neighborhood = neighborhood;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, Job> jobs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection that contains available vehicles.
|
||||||
|
*/
|
||||||
|
private final Collection<Vehicle> vehicles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection that contains all available types.
|
||||||
|
*/
|
||||||
|
private Collection<VehicleType> vehicleTypes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum that indicates type of fleetSize. By default, it is INFINTE
|
||||||
|
*/
|
||||||
|
private FleetSize fleetSize = FleetSize.INFINITE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum that indicates fleetSizeComposition. By default, it is HOMOGENOUS.
|
||||||
|
*/
|
||||||
|
private FleetComposition fleetComposition;
|
||||||
|
|
||||||
|
|
||||||
|
private VehicleRoutingProblem(Builder builder) {
|
||||||
|
this.jobs = builder.jobs;
|
||||||
|
this.fleetComposition = builder.fleetComposition;
|
||||||
|
this.fleetSize = builder.fleetSize;
|
||||||
|
this.vehicles=builder.vehicles;
|
||||||
|
this.vehicleTypes = builder.vehicleTypes;
|
||||||
|
this.transportCosts = builder.transportCosts;
|
||||||
|
this.activityCosts = builder.activityCosts;
|
||||||
|
this.neighborhood = new NeighborhoodImpl(this);
|
||||||
|
log.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[fleetSize="+fleetSize+"][fleetComposition="+fleetComposition+"][#jobs="+jobs.size()+"][#vehicles="+vehicles.size()+"][#vehicleTypes="+vehicleTypes.size()+"]["+
|
||||||
|
"transportCost="+transportCosts+"][activityCosts="+activityCosts+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns fleet-composition.
|
||||||
|
*
|
||||||
|
* @return fleetComposition which is either FleetComposition.HETEROGENEOUS or FleetComposition.HOMOGENEOUS
|
||||||
|
*/
|
||||||
|
public FleetComposition getFleetComposition() {
|
||||||
|
return fleetComposition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFleetComposition(FleetComposition fleetComposition){
|
||||||
|
this.fleetComposition = fleetComposition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns type of fleetSize, either INFINITE or FINITE.
|
||||||
|
*
|
||||||
|
* <p>By default, it is INFINITE.
|
||||||
|
*
|
||||||
|
* @return either FleetSize.INFINITE or FleetSize.FINITE
|
||||||
|
*/
|
||||||
|
public FleetSize getFleetSize() {
|
||||||
|
return fleetSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFleetSize(FleetSize fleetSize){
|
||||||
|
this.fleetSize = fleetSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unmodifiable job map.
|
||||||
|
*
|
||||||
|
* @return unmodifiable jobMap
|
||||||
|
*/
|
||||||
|
public Map<String, Job> getJobs() {
|
||||||
|
return Collections.unmodifiableMap(jobs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entire, unmodifiable collection of types.
|
||||||
|
*
|
||||||
|
* @return unmodifiable collection of types
|
||||||
|
* @see VehicleType
|
||||||
|
*/
|
||||||
|
public Collection<VehicleType> getTypes(){
|
||||||
|
return Collections.unmodifiableCollection(vehicleTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entire, unmodifiable collection of vehicles.
|
||||||
|
*
|
||||||
|
* @return unmodifiable collection of vehicles
|
||||||
|
* @see Vehicle
|
||||||
|
*/
|
||||||
|
public Collection<Vehicle> getVehicles() {
|
||||||
|
return Collections.unmodifiableCollection(vehicles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns routing costs.
|
||||||
|
*
|
||||||
|
* @return routingCosts
|
||||||
|
* @see VehicleRoutingTransportCosts
|
||||||
|
*/
|
||||||
|
public VehicleRoutingTransportCosts getTransportCosts() {
|
||||||
|
return transportCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets routing costs.
|
||||||
|
*
|
||||||
|
* @param costs
|
||||||
|
* @see VehicleRoutingTransportCosts
|
||||||
|
*/
|
||||||
|
public void setTransportCosts(VehicleRoutingTransportCosts costs) {
|
||||||
|
this.transportCosts = costs;
|
||||||
|
logger.info("transport costs set to " + costs.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns activityCosts.
|
||||||
|
*/
|
||||||
|
public VehicleRoutingActivityCosts getActivityCosts(){
|
||||||
|
return activityCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets activityCosts.
|
||||||
|
*/
|
||||||
|
public void setActivityCosts(VehicleRoutingActivityCosts activityCosts){
|
||||||
|
this.activityCosts = activityCosts;
|
||||||
|
logger.info("activtiy costs set to " + activityCosts.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains the solution of a vehicle routing problem and its corresponding costs.
|
||||||
|
*
|
||||||
|
* @author stefan schröder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class VehicleRoutingProblemSolution {
|
||||||
|
|
||||||
|
public static double NO_COST_YET = -9999.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a deep copy of the solution to be copied.
|
||||||
|
*
|
||||||
|
* @param solution2copy
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static VehicleRoutingProblemSolution copyOf(VehicleRoutingProblemSolution solution2copy){
|
||||||
|
return new VehicleRoutingProblemSolution(solution2copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Collection<VehicleRoute> routes;
|
||||||
|
|
||||||
|
private double cost;
|
||||||
|
|
||||||
|
private VehicleRoutingProblemSolution(VehicleRoutingProblemSolution solution){
|
||||||
|
routes = new ArrayList<VehicleRoute>();
|
||||||
|
for(VehicleRoute r : solution.getRoutes()){
|
||||||
|
VehicleRoute route = VehicleRoute.copyOf(r);
|
||||||
|
routes.add(route);
|
||||||
|
}
|
||||||
|
this.cost = solution.getCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a solution with a number of {@link VehicleRoute}s and their corresponding aggregate cost value.
|
||||||
|
*
|
||||||
|
* @param routes
|
||||||
|
* @param cost
|
||||||
|
*/
|
||||||
|
public VehicleRoutingProblemSolution(Collection<VehicleRoute> routes, double cost) {
|
||||||
|
super();
|
||||||
|
this.routes = routes;
|
||||||
|
this.cost = cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Collection<VehicleRoute> getRoutes() {
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public double getCost() {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCost(double cost){
|
||||||
|
this.cost = cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public interface AlgorithmEndsListener extends VehicleRoutingAlgorithmListener{
|
||||||
|
|
||||||
|
void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingAlgorithm;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public interface AlgorithmStartsListener extends VehicleRoutingAlgorithmListener{
|
||||||
|
|
||||||
|
void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
public interface InsertionEndsListener extends InsertionListener {
|
||||||
|
|
||||||
|
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes);
|
||||||
|
}
|
||||||
31
jsprit-core/src/main/java/basics/algo/InsertionListener.java
Normal file
31
jsprit-core/src/main/java/basics/algo/InsertionListener.java
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public interface InsertionListener extends SearchStrategyModuleListener{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
public interface InsertionStartsListener extends InsertionListener {
|
||||||
|
|
||||||
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2Recreate);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public interface IterationEndsListener extends VehicleRoutingAlgorithmListener{
|
||||||
|
|
||||||
|
public void informIterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public interface IterationStartsListener extends VehicleRoutingAlgorithmListener{
|
||||||
|
|
||||||
|
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public interface JobInsertedListener extends InsertionListener{
|
||||||
|
|
||||||
|
public void informJobInserted(int nOfJobsStill2Recreate, Job job2insert, VehicleRoute insertedIn);
|
||||||
|
}
|
||||||
122
jsprit-core/src/main/java/basics/algo/SearchStrategy.java
Normal file
122
jsprit-core/src/main/java/basics/algo/SearchStrategy.java
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
import algorithms.acceptors.SolutionAcceptor;
|
||||||
|
import algorithms.selectors.SolutionSelector;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class SearchStrategy {
|
||||||
|
|
||||||
|
private static Logger logger = Logger.getLogger(SearchStrategy.class);
|
||||||
|
|
||||||
|
private Collection<SearchStrategyModule> searchStrategyModules = new ArrayList<SearchStrategyModule>();
|
||||||
|
|
||||||
|
private SolutionSelector solutionSelector;
|
||||||
|
|
||||||
|
private SolutionAcceptor solutionAcceptor;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public SearchStrategy(SolutionSelector solutionSelector, SolutionAcceptor solutionAcceptor) {
|
||||||
|
super();
|
||||||
|
this.solutionSelector = solutionSelector;
|
||||||
|
this.solutionAcceptor = solutionAcceptor;
|
||||||
|
logger.info("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<SearchStrategyModule> getSearchStrategyModules() {
|
||||||
|
return Collections.unmodifiableCollection(searchStrategyModules);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SolutionSelector getSolutionSelector() {
|
||||||
|
return solutionSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SolutionAcceptor getSolutionAcceptor() {
|
||||||
|
return solutionAcceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "searchStrategy [#modules="+searchStrategyModules.size()+"][selector="+solutionSelector+"][acceptor="+solutionAcceptor+"]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the search-strategy and its according modules, and returns true if a new solution has been accepted.
|
||||||
|
*
|
||||||
|
* <p>This involves three basic steps: 1) Selecting a solution from solutions (input parameter) according to {@link SolutionSelector}, 2) running the modules
|
||||||
|
* ({@link SearchStrategyModule}) on the selectedSolution and 3) accepting the new solution according to {@link SolutionAcceptor}.
|
||||||
|
* <p> Note that after 1) the selected solution is copied, thus the original solution is not modified.
|
||||||
|
* <p> Note also that 3) modifies the input parameter solutions by adding, removing, replacing existing solutions.
|
||||||
|
*
|
||||||
|
* @param vrp
|
||||||
|
* @param solutions which will be modified
|
||||||
|
* @return boolean true if solution has been accepted, false otherwise
|
||||||
|
* @see SolutionSelector, SearchStrategyModule, SolutionAcceptor
|
||||||
|
*/
|
||||||
|
public boolean run(VehicleRoutingProblem vrp, Collection<VehicleRoutingProblemSolution> solutions){
|
||||||
|
VehicleRoutingProblemSolution solution = solutionSelector.selectSolution(solutions);
|
||||||
|
if(solution == null) throw new IllegalStateException("solution is null. check solutionSelector to return an appropiate solution.");
|
||||||
|
VehicleRoutingProblemSolution lastSolution = VehicleRoutingProblemSolution.copyOf(solution);
|
||||||
|
for(SearchStrategyModule module : searchStrategyModules){
|
||||||
|
VehicleRoutingProblemSolution newSolution = module.runAndGetSolution(lastSolution);
|
||||||
|
lastSolution = newSolution;
|
||||||
|
}
|
||||||
|
boolean solutionAccepted = solutionAcceptor.acceptSolution(solutions, lastSolution);
|
||||||
|
return solutionAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void addModule(SearchStrategyModule module){
|
||||||
|
if(module == null) throw new IllegalStateException("module to be added is null.");
|
||||||
|
searchStrategyModules.add(module);
|
||||||
|
logger.info("module added [module="+module+"][#modules="+searchStrategyModules.size()+"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addModuleListener(SearchStrategyModuleListener moduleListener) {
|
||||||
|
for(SearchStrategyModule module : searchStrategyModules){
|
||||||
|
module.addModuleListener(moduleListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
public class SearchStrategyListener {
|
||||||
|
|
||||||
|
}
|
||||||
102
jsprit-core/src/main/java/basics/algo/SearchStrategyManager.java
Normal file
102
jsprit-core/src/main/java/basics/algo/SearchStrategyManager.java
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import util.RandomNumberGeneration;
|
||||||
|
|
||||||
|
|
||||||
|
public class SearchStrategyManager {
|
||||||
|
|
||||||
|
private List<SearchStrategyListener> searchStrategyListeners = new ArrayList<SearchStrategyListener>();
|
||||||
|
|
||||||
|
private List<SearchStrategy> strategies = new ArrayList<SearchStrategy>();
|
||||||
|
|
||||||
|
private List<Double> probabilities = new ArrayList<Double>();
|
||||||
|
|
||||||
|
private Random random = RandomNumberGeneration.getRandom();
|
||||||
|
|
||||||
|
private double sumOfProbabilities = 0;
|
||||||
|
|
||||||
|
public void setRandom(Random random) {
|
||||||
|
this.random = random;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<SearchStrategy> getStrategies() {
|
||||||
|
return Collections.unmodifiableList(strategies);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<Double> getProbabilities() {
|
||||||
|
return Collections.unmodifiableList(probabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a new search strategy. the probability must be within [0,1].
|
||||||
|
* @param strategy
|
||||||
|
* @param probability
|
||||||
|
*/
|
||||||
|
public void addStrategy(SearchStrategy strategy, double probability){
|
||||||
|
if(strategy == null){
|
||||||
|
throw new IllegalStateException("strategy is null. make sure adding a valid strategy.");
|
||||||
|
}
|
||||||
|
if(probability > 1.0){
|
||||||
|
throw new IllegalStateException("probability is higher than one, but it must be within [0,1].");
|
||||||
|
}
|
||||||
|
if(probability < 0.0){
|
||||||
|
throw new IllegalStateException("probability is lower than zero, but it must be within [0,1].");
|
||||||
|
}
|
||||||
|
strategies.add(strategy);
|
||||||
|
probabilities.add(probability);
|
||||||
|
sumOfProbabilities += probability;
|
||||||
|
if(sumOfProbabilities > 1.0){
|
||||||
|
throw new IllegalStateException("total probability of all strategies is higher than one, but it must be within [0,1].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchStrategy getRandomStrategy() {
|
||||||
|
if(random == null) throw new IllegalStateException("randomizer is null. make sure you set random object correctly");
|
||||||
|
double randomFig = random.nextDouble();
|
||||||
|
double sumWeight = 0.0;
|
||||||
|
for (int i = 0; i < probabilities.size(); i++) {
|
||||||
|
sumWeight += probabilities.get(i);
|
||||||
|
if (randomFig < sumWeight) {
|
||||||
|
return strategies.get(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("no seaarch-strategy found");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSearchStrategyListener(SearchStrategyListener strategyListener){
|
||||||
|
searchStrategyListeners.add(strategyListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSearchStrategyModuleListener(SearchStrategyModuleListener moduleListener){
|
||||||
|
for(SearchStrategy s : strategies){
|
||||||
|
s.addModuleListener(moduleListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
public interface SearchStrategyModule {
|
||||||
|
|
||||||
|
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution);
|
||||||
|
|
||||||
|
public String getName();
|
||||||
|
|
||||||
|
public void addModuleListener(SearchStrategyModuleListener moduleListener);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
public interface SearchStrategyModuleListener {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public interface StrategySelectedListener extends VehicleRoutingAlgorithmListener{
|
||||||
|
|
||||||
|
void informSelectedStrategy(String strategyName, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue