├── LICENSE ├── README.md ├── heuristicsearch ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── src │ └── main │ │ ├── java │ │ └── xyz │ │ │ └── thepathfinder │ │ │ └── routing │ │ │ ├── domain │ │ │ ├── CommodityAction.java │ │ │ ├── CommodityDropoff.java │ │ │ ├── CommodityPickup.java │ │ │ ├── RouteAction.java │ │ │ ├── RoutingSolution.java │ │ │ └── Transport.java │ │ │ ├── score │ │ │ ├── NaiveDifficultyComparator.java │ │ │ └── RoutingScoreCalculator.java │ │ │ └── service │ │ │ ├── ProblemDescription.java │ │ │ ├── ProblemSolution.java │ │ │ └── RoutingService.java │ │ ├── resources │ │ └── xyz │ │ │ └── thepathfinder │ │ │ └── routing │ │ │ └── solverconfig.xml │ │ └── webapp │ │ └── WEB-INF │ │ └── web.xml └── stress_test │ ├── tests.py │ └── top.png ├── linearprogramming ├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE ├── README.md ├── REQUIRE ├── docs │ ├── Route Optimization Model.pdf │ ├── math.docx │ ├── objectives.md │ ├── request.json │ └── response.json ├── src │ ├── PathfinderRouting.jl │ ├── server.jl │ ├── server.sh │ └── solve.jl ├── stress_test │ ├── Routing Stress Test Results.md │ ├── out.jpg │ ├── profile-4-vehicles-3-commodities.txt │ └── tests.py ├── test │ ├── runtests.jl │ └── solve.jl └── util │ ├── min_sum_diff_wait.py │ └── sample_request.py ├── masterrouter ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── app.rb ├── config.ru └── config.yml └── simulatedannealing ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── src └── main │ ├── java │ └── xyz │ │ └── thepathfinder │ │ └── routing │ │ ├── domain │ │ ├── CommodityAction.java │ │ ├── CommodityDropoff.java │ │ ├── CommodityPickup.java │ │ ├── CommodityStart.java │ │ ├── RouteAction.java │ │ ├── Transport.java │ │ ├── VRPSearchState.java │ │ └── VehicleRoutingProblem.java │ │ └── service │ │ ├── ProblemDescription.java │ │ ├── ProblemSolution.java │ │ └── RoutingService.java │ └── webapp │ └── WEB-INF │ └── web.xml └── stress_test ├── tests.py └── top.png /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Adam Michael 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The k-Vehicle Routing Optimization Problem 2 | 3 | At the core of Pathfinder is the k-Vehicle Routing Routing (kVRP). kVRP is known to be NP-complete, which is not the type of problem fast-moving developers with a product to ship should be worrying about. This is the core of why we created Pathfinder. 4 | 5 | 6 | ## The problem 7 | 8 | Traditionally, kVRP concerns partitioning and ordering a set of locations between a set of vehicles. Common examples include mail delivery or scheduling repairmen. 9 | 10 | Pathfinder solves a more constrained variant of kVRP. In Pathfinder, solutions are constrained by: 11 | * Vehicle capacities. Pathfinder allows for arbitrary capacity vectors that transports are initialized with and are updated when servicing commodities. 12 | * Pickup-dropoff relationships. It would not make sense to drop off a commodity before picking it up or for a vehicle to drop off a commodity that a different vehicle picked up. 13 | * Initial conditions. Pathfinder optimizes routes in real-time, which includes the scenario when commodities are already en-route. 14 | * Arbitrary objective functions. Some kVRP approximation algorithms assume that the goal is to minimize distance and take advantage of properties of Euclidean space. 15 | 16 | 17 | ## The solution 18 | 19 | On every computation, Pathfinder uses three optimization approaches and selects the best route yet discovered after a fixed period of time. The code for each of the three approaches, as well as the "master router" that selects the optimal route is all contained in this repository. 20 | 21 | Each approach works well for some scenarios and poorly for others. The three approaches Pathfinder employs are: 22 | * Linear programming using Julia, JuMP and CLP. Code is in `/linearprogramming` 23 | * Heuristic search using Optaplanner. Code is in `/heuristicsearch`. 24 | * Simmulated annealing using a built-from-scratch implementation. Code is in `/simulatedannealing` and at [https://github.com/csse497/simulatedannealing](https://github.com/csse497/simulatedannealing). 25 | 26 | ## LICENSE 27 | 28 | [MIT](https://raw.githubusercontent.com/CSSE497/pathfinder-routing/master/LICENSE). 29 | -------------------------------------------------------------------------------- /heuristicsearch/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.idea 3 | .gradle 4 | build/ 5 | gradle-app.setting 6 | !gradle-wrapper.jar 7 | .gradletasknamecache 8 | .DS_Store 9 | /*.java 10 | /src/main/flex/*.java 11 | /src/main/java/edu/rosehulman/minijavac/generated 12 | *~ 13 | gradlew.bat 14 | settings.gradle 15 | out/ 16 | classes/ 17 | -------------------------------------------------------------------------------- /heuristicsearch/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Adam Michael 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /heuristicsearch/README.md: -------------------------------------------------------------------------------- 1 | # Pathfinder Routing Server v2 2 | 3 | The first iteration just wasn't fast enough, so it's time for a new approach. 4 | -------------------------------------------------------------------------------- /heuristicsearch/build.gradle: -------------------------------------------------------------------------------- 1 | group 'xyz.thepathfinder.routing' 2 | 3 | apply plugin: 'java' 4 | apply plugin: 'war' 5 | 6 | repositories { 7 | mavenCentral() 8 | maven { 9 | url 'http://repository.jboss.org/nexus/content/groups/public-jboss' 10 | } 11 | } 12 | 13 | dependencies { 14 | compile 'com.sun.jersey:jersey-core:1.19.1' 15 | compile 'com.sun.jersey:jersey-json:1.19.1' 16 | compile 'com.sun.jersey:jersey-server:1.19.1' 17 | compile 'com.sun.jersey:jersey-servlet:1.19.1' 18 | compile 'javax.ws.rs:jsr311-api:1.1.1' 19 | compile 'org.optaplanner:optaplanner-core:6.3.0.Final' 20 | compile 'org.slf4j:slf4j-api:1.7.19' 21 | compile 'org.slf4j:slf4j-simple:1.7.19' 22 | testCompile group: 'junit', name: 'junit', version: '4.11' 23 | } 24 | -------------------------------------------------------------------------------- /heuristicsearch/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CSSE497/pathfinder-routing/c234fdfe8eebc2799b39f7071cc0091884f71a26/heuristicsearch/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /heuristicsearch/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Mar 17 20:48:04 EDT 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip 7 | -------------------------------------------------------------------------------- /heuristicsearch/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/domain/CommodityAction.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | import org.optaplanner.core.api.domain.entity.PlanningEntity; 4 | import org.optaplanner.core.api.domain.variable.AnchorShadowVariable; 5 | import org.optaplanner.core.api.domain.variable.PlanningVariable; 6 | import org.optaplanner.core.api.domain.variable.PlanningVariableGraphType; 7 | 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | import xyz.thepathfinder.routing.score.NaiveDifficultyComparator; 12 | 13 | @PlanningEntity(difficultyComparatorClass = NaiveDifficultyComparator.class) 14 | public abstract class CommodityAction implements RouteAction { 15 | Transport transport; 16 | CommodityAction nextCommodityAction; 17 | RouteAction previousRouteAction; 18 | Map distances = new HashMap<>(); 19 | Map capacities; 20 | int id; 21 | 22 | @Override 23 | @AnchorShadowVariable(sourceVariableName = "previousRouteAction") 24 | public Transport getTransport() { 25 | return transport; 26 | } 27 | 28 | public void setTransport(Transport transport) { 29 | this.transport = transport; 30 | } 31 | 32 | @Override 33 | public CommodityAction getNextCommodityAction() { 34 | return nextCommodityAction; 35 | } 36 | 37 | @Override 38 | public void setNextCommodityAction(CommodityAction commodityAction) { 39 | nextCommodityAction = commodityAction; 40 | } 41 | 42 | @PlanningVariable(valueRangeProviderRefs = {"transportRange", "commodityActionRange"}, 43 | graphType = PlanningVariableGraphType.CHAINED) 44 | public RouteAction getPreviousRouteAction() { 45 | return previousRouteAction; 46 | } 47 | 48 | public void setPreviousRouteAction(RouteAction routeAction) { 49 | previousRouteAction = routeAction; 50 | } 51 | 52 | @Override 53 | public long distanceTo(RouteAction routeAction) { 54 | return distances.getOrDefault(routeAction, Long.MAX_VALUE); 55 | } 56 | 57 | @Override 58 | public void setDistance(RouteAction routeAction, long distance) { 59 | distances.put(routeAction, distance); 60 | } 61 | 62 | @Override 63 | public int id() { 64 | return id; 65 | } 66 | 67 | @Override 68 | public int getCapacity(String key) { 69 | return capacities.getOrDefault(key, 0); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/domain/CommodityDropoff.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class CommodityDropoff extends CommodityAction { 7 | RouteAction pickup; 8 | 9 | public CommodityDropoff() { } 10 | 11 | public CommodityDropoff(int id, Map capacities) { 12 | this.id = id; 13 | this.capacities = capacities == null ? new HashMap<>() : capacities; 14 | } 15 | 16 | public RouteAction getPickup() { 17 | return this.pickup; 18 | } 19 | 20 | public void setPickup(RouteAction pickup) { 21 | this.pickup = pickup; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/domain/CommodityPickup.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | import org.optaplanner.core.api.domain.entity.PlanningEntity; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | @PlanningEntity 9 | public class CommodityPickup extends CommodityAction { 10 | CommodityDropoff dropoff; 11 | 12 | public CommodityPickup() { } 13 | 14 | public CommodityPickup(int id, Map capacities) { 15 | this.id = id; 16 | this.capacities = capacities == null ? new HashMap<>() : capacities; 17 | } 18 | 19 | public CommodityDropoff getDropoff() { 20 | return dropoff; 21 | } 22 | 23 | public void setDropoff(CommodityDropoff dropoff) { 24 | this.dropoff = dropoff; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/domain/RouteAction.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | import org.optaplanner.core.api.domain.entity.PlanningEntity; 4 | import org.optaplanner.core.api.domain.variable.InverseRelationShadowVariable; 5 | 6 | @PlanningEntity 7 | public interface RouteAction { 8 | 9 | Transport getTransport(); 10 | 11 | @InverseRelationShadowVariable(sourceVariableName = "previousRouteAction") 12 | CommodityAction getNextCommodityAction(); 13 | void setNextCommodityAction(CommodityAction commodityAction); 14 | 15 | long distanceTo(RouteAction routeAction); 16 | 17 | void setDistance(RouteAction routeAction, long distance); 18 | 19 | int id(); 20 | 21 | int getCapacity(String key); 22 | } 23 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/domain/RoutingSolution.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty; 4 | import org.optaplanner.core.api.domain.solution.PlanningSolution; 5 | import org.optaplanner.core.api.domain.solution.Solution; 6 | import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider; 7 | import org.optaplanner.core.api.score.buildin.hardsoftlong.HardSoftLongScore; 8 | 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.Collection; 12 | import java.util.List; 13 | import java.util.stream.Collector; 14 | import java.util.stream.Collectors; 15 | 16 | import xyz.thepathfinder.routing.service.ProblemSolution; 17 | 18 | import static java.util.stream.Collectors.toList; 19 | 20 | @PlanningSolution 21 | public class RoutingSolution implements Solution { 22 | 23 | HardSoftLongScore score; 24 | List transportList; 25 | List commodityActionList; 26 | 27 | @Override 28 | public HardSoftLongScore getScore() { 29 | return score; 30 | } 31 | 32 | @Override 33 | public void setScore(HardSoftLongScore score) { 34 | this.score = score; 35 | } 36 | 37 | @Override 38 | public Collection getProblemFacts() { 39 | List routeActions = new ArrayList<>(); 40 | routeActions.addAll(transportList); 41 | routeActions.addAll(commodityActionList); 42 | return routeActions; 43 | } 44 | 45 | @PlanningEntityCollectionProperty 46 | @ValueRangeProvider(id = "transportRange") 47 | public List getTransportList() { 48 | return transportList; 49 | } 50 | 51 | public void setTransportList(List transports) { 52 | transportList = transports; 53 | } 54 | 55 | @PlanningEntityCollectionProperty 56 | @ValueRangeProvider(id = "commodityActionRange") 57 | public List getCommodityActionList() { 58 | return commodityActionList; 59 | } 60 | 61 | public void setCommodityActionList(List commodityActions) { 62 | commodityActionList = commodityActions; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/domain/Transport.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | public class Transport implements RouteAction { 9 | 10 | CommodityAction nextCommodityAction; 11 | int id; 12 | Map distances = new HashMap<>(); 13 | Map capacities; 14 | 15 | public Transport() { 16 | 17 | } 18 | 19 | public Transport(int id, Map capacities) { 20 | this.id = id; 21 | this.capacities = capacities == null ? new HashMap<>() : capacities; 22 | } 23 | 24 | @Override 25 | public Transport getTransport() { 26 | return this; 27 | } 28 | 29 | @Override 30 | public CommodityAction getNextCommodityAction() { 31 | return nextCommodityAction; 32 | } 33 | 34 | @Override 35 | public void setNextCommodityAction(CommodityAction commodityAction) { 36 | nextCommodityAction = commodityAction; 37 | } 38 | 39 | public List getPathfinderRoute() { 40 | CommodityAction action = nextCommodityAction; 41 | List route = new ArrayList<>(); 42 | route.add(id); 43 | while (action != null) { 44 | route.add(action.id()); 45 | action = action.getNextCommodityAction(); 46 | } 47 | return route; 48 | } 49 | 50 | public List getRoute() { 51 | CommodityAction action = nextCommodityAction; 52 | List route = new ArrayList<>(); 53 | while (action != null) { 54 | route.add(action); 55 | action = action.getNextCommodityAction(); 56 | } 57 | return route; 58 | } 59 | 60 | @Override 61 | public long distanceTo(RouteAction routeAction) { 62 | return distances.get(routeAction); 63 | } 64 | 65 | @Override 66 | public void setDistance(RouteAction routeAction, long distance) { 67 | distances.put(routeAction, distance); 68 | } 69 | 70 | @Override 71 | public int id() { 72 | return id; 73 | } 74 | 75 | @Override public int getCapacity(String key) { 76 | return capacities.getOrDefault(key, 0); 77 | } 78 | 79 | public Map getCapacities() { 80 | return capacities; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/score/NaiveDifficultyComparator.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.score; 2 | 3 | import java.util.Comparator; 4 | 5 | import xyz.thepathfinder.routing.domain.CommodityAction; 6 | import xyz.thepathfinder.routing.domain.CommodityDropoff; 7 | import xyz.thepathfinder.routing.domain.CommodityPickup; 8 | import xyz.thepathfinder.routing.domain.RouteAction; 9 | 10 | public class NaiveDifficultyComparator implements Comparator { 11 | 12 | @Override 13 | public int compare(CommodityAction o1, CommodityAction o2) { 14 | if (o1 instanceof CommodityDropoff && o2 instanceof CommodityPickup) { 15 | return 1; 16 | } else if (o1 instanceof CommodityPickup && o2 instanceof CommodityDropoff) { 17 | return -1; 18 | } else { 19 | return 0; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/score/RoutingScoreCalculator.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.score; 2 | 3 | import org.optaplanner.core.api.score.Score; 4 | import org.optaplanner.core.api.score.buildin.hardsoftlong.HardSoftLongScore; 5 | import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator; 6 | 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | import xyz.thepathfinder.routing.domain.CommodityAction; 12 | import xyz.thepathfinder.routing.domain.CommodityDropoff; 13 | import xyz.thepathfinder.routing.domain.RoutingSolution; 14 | 15 | import static java.util.stream.Collectors.summingLong; 16 | 17 | public class RoutingScoreCalculator implements EasyScoreCalculator { 18 | 19 | @Override 20 | public Score calculateScore(RoutingSolution solution) { 21 | long hardScore = 0; 22 | long softScore = 0; 23 | hardScore -= pickupOutOfOrderViolations(solution); 24 | hardScore -= capacitiesViolated(solution); 25 | softScore -= getTotalDistance(solution); 26 | System.out.println("Score: " + hardScore + ", " + softScore); 27 | return HardSoftLongScore.valueOf(hardScore, softScore); 28 | } 29 | 30 | static long pickupOutOfOrderViolations(RoutingSolution solution) { 31 | return solution.getTransportList().stream().collect(summingLong(t -> { 32 | List route = t.getRoute(); 33 | long violations = 0; 34 | for (int i = 0; i < route.size(); i++) { 35 | if (route.get(i) instanceof CommodityDropoff) { 36 | CommodityDropoff dropoff = (CommodityDropoff) route.get(i); 37 | if (!dropoff.getPickup().equals(t)) { 38 | int position = route.indexOf(dropoff.getPickup()); 39 | if (position < 0 || position >= i) { 40 | violations++; 41 | } 42 | } 43 | } 44 | } 45 | return violations; 46 | })); 47 | } 48 | 49 | static long capacitiesViolated(RoutingSolution solution) { 50 | return solution.getTransportList().stream().collect(summingLong(t -> { 51 | Map capacities = new HashMap<>(t.getCapacities()); 52 | CommodityAction commodityAction = t.getNextCommodityAction(); 53 | while (commodityAction != null) { 54 | for (String key : capacities.keySet()) { 55 | capacities.put(key, capacities.get(key) - commodityAction.getCapacity(key)); 56 | } 57 | if (capacities.values().stream().anyMatch(x -> x < 0)) { 58 | return 1; 59 | } 60 | commodityAction = commodityAction.getNextCommodityAction(); 61 | } 62 | return 0; 63 | })); 64 | } 65 | 66 | static long getTotalDistance(RoutingSolution solution) { 67 | return solution.getTransportList().stream().collect( 68 | summingLong(t -> getPathDistance(t.getNextCommodityAction()))); 69 | } 70 | 71 | static long getPathDistance(CommodityAction commodityAction) { 72 | if (commodityAction == null) { 73 | return 0; 74 | } else { 75 | return commodityAction.distanceTo(commodityAction.getPreviousRouteAction()) + 76 | getPathDistance(commodityAction.getNextCommodityAction()); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/service/ProblemDescription.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.service; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.stream.Collectors; 9 | 10 | import xyz.thepathfinder.routing.domain.CommodityAction; 11 | import xyz.thepathfinder.routing.domain.CommodityDropoff; 12 | import xyz.thepathfinder.routing.domain.CommodityPickup; 13 | import xyz.thepathfinder.routing.domain.RouteAction; 14 | import xyz.thepathfinder.routing.domain.RoutingSolution; 15 | import xyz.thepathfinder.routing.domain.Transport; 16 | 17 | import static java.util.function.Function.identity; 18 | 19 | public class ProblemDescription { 20 | private List transports; 21 | private Map commodities; 22 | private Integer[][] durations; 23 | private Integer[][] distances; 24 | private Map> capacities; 25 | private Map> parameters; 26 | private String objective; 27 | 28 | public void setTransports(List transports) { 29 | this.transports = transports; 30 | } 31 | 32 | public void setCommodities(Map commodities) { 33 | this.commodities = commodities; 34 | } 35 | 36 | public void setDurations(Integer[][] durations) { 37 | this.durations = durations; 38 | } 39 | 40 | public void setDistances(Integer[][] distances) { 41 | this.distances = distances; 42 | } 43 | 44 | public void setCapacities(Map> capacities) { 45 | this.capacities = capacities; 46 | } 47 | 48 | public void setParameters(Map> parameters) { 49 | this.parameters = parameters; 50 | } 51 | 52 | public void setObjective(String objective) { 53 | this.objective = objective; 54 | } 55 | 56 | public List getTransports() { 57 | return transports; 58 | } 59 | 60 | public Map getCommodities() { 61 | return commodities; 62 | } 63 | 64 | public Integer[][] getDurations() { 65 | return durations; 66 | } 67 | 68 | public Integer[][] getDistances() { 69 | return distances; 70 | } 71 | 72 | public Map> getCapacities() { 73 | return capacities; 74 | } 75 | 76 | public Map> getParameters() { 77 | return parameters; 78 | } 79 | 80 | public String getObjective() { 81 | return objective; 82 | } 83 | 84 | public RoutingSolution createEmptyRoutingSolution() { 85 | // Flip the capacities array 86 | Map> flippedCapacities = new HashMap<>(); 87 | for (Map.Entry> capacityListEntry : capacities.entrySet()) { 88 | for (Map.Entry capacityEntry : capacityListEntry.getValue().entrySet()) { 89 | flippedCapacities.putIfAbsent(capacityEntry.getKey(), new HashMap<>()); 90 | flippedCapacities.get(capacityEntry.getKey()).put(capacityListEntry.getKey(), capacityEntry.getValue()); 91 | } 92 | } 93 | 94 | // Initialize transports and commodities 95 | Map transportMap = transports.stream().collect( 96 | Collectors.toMap(identity(), v -> new Transport(v, flippedCapacities.get(v)))); 97 | Map commodityActions = new HashMap<>(); 98 | for (Map.Entry commodityEntry : commodities.entrySet()) { 99 | int dropoffId = commodityEntry.getKey(); 100 | CommodityDropoff dropoff = new CommodityDropoff(dropoffId, flippedCapacities.get(dropoffId)); 101 | commodityActions.put(commodityEntry.getKey(), dropoff); 102 | if (transportMap.containsKey(commodityEntry.getKey())) { 103 | dropoff.setPickup(transportMap.get(commodityEntry.getKey())); 104 | } else { 105 | int pickupId = commodityEntry.getValue(); 106 | CommodityPickup pickup = new CommodityPickup(pickupId, flippedCapacities.get(pickupId)); 107 | commodityActions.put(commodityEntry.getValue(), pickup); 108 | dropoff.setPickup(pickup); 109 | pickup.setDropoff(dropoff); 110 | } 111 | } 112 | 113 | // Set distance lists for route actions 114 | Map routeActions = new HashMap<>(); 115 | routeActions.putAll(transportMap); 116 | routeActions.putAll(commodityActions); 117 | for (int r = 0; r < distances.length; r++) { 118 | for (int c = 0; c < distances[r].length; c++) { 119 | if (r != c && routeActions.containsKey(r+1) && routeActions.containsKey(c+1)) { 120 | System.out.println("Getting distance["+r+","+c+"]"); 121 | routeActions.get(r+1).setDistance(routeActions.get(c+1), distances[r][c]); 122 | } 123 | } 124 | } 125 | 126 | // Construct solution 127 | RoutingSolution solution = new RoutingSolution(); 128 | solution.setCommodityActionList(new ArrayList<>(commodityActions.values())); 129 | solution.setTransportList(new ArrayList<>(transportMap.values())); 130 | return solution; 131 | } 132 | 133 | @Override 134 | public String toString() { 135 | return new StringBuilder() 136 | .append("Transports: ").append(transports).append("\n") 137 | .append("Commodities: " ).append(commodities).append("\n") 138 | .append("Distances: ").append(Arrays.deepToString(distances)).append("\n") 139 | .append("Durations: ").append(Arrays.deepToString(durations)).append("\n") 140 | .append("Capacities: ").append(capacities).append("\n") 141 | .append("Parameters: ").append(parameters).append("\n") 142 | .append("Objective: ").append(objective) 143 | .toString(); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/service/ProblemSolution.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.service; 2 | 3 | import java.util.List; 4 | 5 | import xyz.thepathfinder.routing.domain.RoutingSolution; 6 | import xyz.thepathfinder.routing.domain.Transport; 7 | 8 | import static java.util.stream.Collectors.toList; 9 | 10 | public class ProblemSolution { 11 | private List> routes; 12 | 13 | public ProblemSolution() { } 14 | 15 | public static ProblemSolution create(RoutingSolution solution) { 16 | return new ProblemSolution(solution.getTransportList().stream() 17 | .map(Transport::getPathfinderRoute).collect(toList())); 18 | } 19 | 20 | public ProblemSolution(List> routes) { 21 | this.routes = routes; 22 | } 23 | 24 | public void setRoutes(List> routes) { 25 | this.routes = routes; 26 | } 27 | 28 | public List> getRoutes() { 29 | return routes; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/java/xyz/thepathfinder/routing/service/RoutingService.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.service; 2 | 3 | import org.optaplanner.core.api.solver.Solver; 4 | import org.optaplanner.core.api.solver.SolverFactory; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import javax.ws.rs.Consumes; 9 | import javax.ws.rs.POST; 10 | import javax.ws.rs.Path; 11 | import javax.ws.rs.Produces; 12 | import javax.ws.rs.core.MediaType; 13 | 14 | import xyz.thepathfinder.routing.domain.RoutingSolution; 15 | 16 | @Path("/") 17 | public class RoutingService { 18 | Logger logger = LoggerFactory.getLogger(RoutingService.class); 19 | 20 | public static final String SOLVER_CONFIG = "xyz/thepathfinder/routing/solverconfig.xml"; 21 | 22 | @POST 23 | @Consumes(MediaType.APPLICATION_JSON) 24 | @Produces(MediaType.APPLICATION_JSON) 25 | public ProblemSolution solveProblem(ProblemDescription problemDescription) { 26 | logger.info("Received request to route: " + problemDescription); 27 | SolverFactory solverFactory = SolverFactory.createFromXmlResource(SOLVER_CONFIG); 28 | Solver solver = solverFactory.buildSolver(); 29 | RoutingSolution routingSolution = problemDescription.createEmptyRoutingSolution(); 30 | solver.solve(routingSolution); 31 | return ProblemSolution.create((RoutingSolution) solver.getBestSolution()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/resources/xyz/thepathfinder/routing/solverconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | xyz.thepathfinder.routing.domain.RoutingSolution 4 | xyz.thepathfinder.routing.domain.CommodityAction 5 | xyz.thepathfinder.routing.domain.RouteAction 6 | 7 | 8 | HARD_SOFT_LONG 9 | xyz.thepathfinder.routing.score.RoutingScoreCalculator\ 10 | ONLY_DOWN 11 | 12 | 13 | 14 | 2 15 | 5 16 | 17 | 18 | FIRST_FIT_DECREASING 19 | 20 | 21 | 22 | 23 | 24 | 25 | true 26 | 27 | 28 | true 29 | 30 | 31 | 32 | 200 33 | 34 | 35 | 1 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /heuristicsearch/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pathfinder Routing Server 4 | 5 | routing 6 | com.sun.jersey.spi.container.servlet.ServletContainer 7 | 8 | com.sun.jersey.config.property.packages 9 | xyz.thepathfinder.routing.service 10 | 11 | 12 | com.sun.jersey.api.json.POJOMappingFeature 13 | true 14 | 15 | 1 16 | 17 | 18 | routing 19 | /* 20 | 21 | 22 | -------------------------------------------------------------------------------- /heuristicsearch/stress_test/tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import requests 5 | import time 6 | import random 7 | 8 | M = 30 9 | distance_matrix = [[0 if r==c else random.choice(range(1, 100)) for c in range(0,30)] for r in range (0, 30)] 10 | 11 | def data(t, c): 12 | if t + 2*c > len(distance_matrix): 13 | raise Exception 14 | transports = range(1, t + 1) 15 | commodities = { x: x + c for x in range(t + 1, t + c + 1) } 16 | return { 17 | 'transports': transports, 18 | 'commodities': commodities, 19 | 'durations': distance_matrix, 20 | 'distances': distance_matrix, 21 | 'capacities': { 22 | 'capacity': dict({t: 1 for t in transports}, **dict({commodities[d]: 1 for d in commodities}, **{d: -1 for d in commodities})) 23 | }, 24 | 'parameters': { 25 | }, 26 | 'objective': """ 27 | @setObjective(model, Min, sum{distance[i],i=TA}) 28 | """ 29 | } 30 | 31 | def time_request(url, data): 32 | start = time.time() 33 | r = requests.post(url, json=data) 34 | print "{0:.2f}".format(time.time() - start), 35 | print "(" + str(route_length(json.loads(r.text)['routes'])) +")|", 36 | #print r.status_code 37 | #print 'Length: ' + str(route_length(json.loads(r.text)['routes'])) 38 | #return time.time() - start 39 | 40 | def test(t, c): 41 | #print "Time for {} transports and {} commodities".format(t, c) 42 | time_request('http://routing2.thepathfinder.xyz', data(t, c)) 43 | #print 'Time: ' + str(time_request('http://routing2.thepathfinder.xyz', data(t, c))) 44 | 45 | def testlocal(t, c): 46 | time_request('http://localhost:8080/routing', data(t, c)) 47 | 48 | def testold(t, c): 49 | time_request('http://routing.thepathfinder.xyz', data(t, c)) 50 | 51 | def route_length(routes): 52 | #print 'Routes: ' + str(routes) 53 | return sum(distance_matrix[a-1][b-1] for [a, b] in sum([zip(r[:len(r)-1],r[1:]) for r in routes], [])) 54 | 55 | if __name__ == '__main__': 56 | print '|T=1|', 57 | [test(1,c) for c in range(1, 5)] 58 | print 59 | print '|T=2|', 60 | [test(2,c) for c in range(1, 4)] 61 | print 62 | print '|T=3|', 63 | [test(3,c) for c in range(1, 4)] 64 | print 65 | print '|T=4|', 66 | [test(4,c) for c in range(1, 4)] 67 | print 68 | print '|T=5|', 69 | [test(5,c) for c in range(1, 4)] 70 | print 71 | print '|T=6|', 72 | [test(6,c) for c in range(1, 3)] 73 | print 74 | print '|T=7|', 75 | [test(7,c) for c in range(1, 3)] 76 | print 77 | print '|T=8|', 78 | [test(8,c) for c in range(1, 3)] 79 | print 80 | print '|T=9|', 81 | [test(9,c) for c in range(1, 3)] 82 | print 'OLD' 83 | print '|T=1|', 84 | [testold(1,c) for c in range(1, 5)] 85 | print 86 | print '|T=2|', 87 | [testold(2,c) for c in range(1, 4)] 88 | print 89 | print '|T=3|', 90 | [testold(3,c) for c in range(1, 4)] 91 | print 92 | print '|T=4|', 93 | [testold(4,c) for c in range(1, 4)] 94 | print 95 | print '|T=5|', 96 | [testold(5,c) for c in range(1, 4)] 97 | print 98 | print '|T=6|', 99 | [testold(6,c) for c in range(1, 3)] 100 | print 101 | print '|T=7|', 102 | [testold(7,c) for c in range(1, 3)] 103 | print 104 | print '|T=8|', 105 | [testold(8,c) for c in range(1, 3)] 106 | print 107 | print '|T=9|', 108 | [testold(9,c) for c in range(1, 3)] 109 | 110 | -------------------------------------------------------------------------------- /heuristicsearch/stress_test/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CSSE497/pathfinder-routing/c234fdfe8eebc2799b39f7071cc0091884f71a26/heuristicsearch/stress_test/top.png -------------------------------------------------------------------------------- /linearprogramming/.gitignore: -------------------------------------------------------------------------------- 1 | *.jl.cov 2 | *.jl.mem 3 | -------------------------------------------------------------------------------- /linearprogramming/.travis.yml: -------------------------------------------------------------------------------- 1 | language: julia 2 | sudo: false 3 | os: 4 | - linux 5 | julia: 6 | - 0.4 7 | script: 8 | - julia -e 'Pkg.clone(pwd()); Pkg.build("PathfinderRouting"); Pkg.test("PathfinderRouting", coverage=true)' 9 | after_success: 10 | - julia -e 'cd(Pkg.dir("PathfinderRouting")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(process_folder())' 11 | -------------------------------------------------------------------------------- /linearprogramming/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | MAINTAINER Adam Michael 3 | 4 | # Julia 5 | RUN apt-get update && apt-get install -y wget python-software-properties software-properties-common libglfw2 libglfw-dev 6 | RUN add-apt-repository ppa:staticfloat/juliareleases && apt-get update 7 | RUN apt-get install -y julia 8 | RUN apt-get install -y build-essential cmake xorg-dev libglu1-mesa-dev git 9 | RUN apt-get install -y libgmp-dev 10 | RUN julia -e "Pkg.resolve()" 11 | 12 | # Dependencies 13 | ADD REQUIRE /.julia/v0.4/REQUIRE 14 | RUN julia -e "Pkg.resolve()" 15 | RUN julia -e 'Pkg.add("Clp")' 16 | RUN julia -e 'Pkg.add("HttpServer")' 17 | RUN julia -e 'Pkg.add("JuMP")' 18 | RUN julia -e 'Pkg.add("JSON")' 19 | RUN julia -e 'Pkg.add("Logging")' 20 | 21 | 22 | # Server 23 | ADD src / 24 | RUN chmod +x /server.sh 25 | CMD ["/server.sh"] 26 | -------------------------------------------------------------------------------- /linearprogramming/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Adam Michael 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /linearprogramming/README.md: -------------------------------------------------------------------------------- 1 | # Pathfinder Route Optimization 2 | 3 | While the bulk of the Pathfinder business logic is contained in the [Scala Play! backend server](https://github.com/csse497/pathfinder-server), the problem of route optimization is implemented as a stand-alone Julia microservice. 4 | 5 | Documentation for Pathfinder route optimization is hosted on [pathfinder.readme.io](https://pathfinder.readme.io). It is split into [route optimization](https://pathfinder.readme.io/docs/route-optimization-as-a-linear-program) and the [objective function dsl](https://pathfinder.readme.io/docs/objective-function-dsl). 6 | -------------------------------------------------------------------------------- /linearprogramming/REQUIRE: -------------------------------------------------------------------------------- 1 | julia 0.4 2 | 3 | HttpServer 4 | JuMP 5 | Logging 6 | JSON 7 | Clp 8 | -------------------------------------------------------------------------------- /linearprogramming/docs/Route Optimization Model.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CSSE497/pathfinder-routing/c234fdfe8eebc2799b39f7071cc0091884f71a26/linearprogramming/docs/Route Optimization Model.pdf -------------------------------------------------------------------------------- /linearprogramming/docs/math.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CSSE497/pathfinder-routing/c234fdfe8eebc2799b39f7071cc0091884f71a26/linearprogramming/docs/math.docx -------------------------------------------------------------------------------- /linearprogramming/docs/objectives.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Last updated on January 27, 2016 by Adam Michael 4 | 5 | This document defines The Pathfinder's routing model and how it can be used to configure capacities, parameters and custom objective functions to specify the routing behaviour for your application. 6 | 7 | # Contents 8 | 9 | 1. [LP Model](#Model) 10 | 2. [Objective Function DSL](#DSL) 11 | 12 | # LP Model 13 | 14 | ## Cluster 15 | A cluster is a set of vertexes. Each transport starting location, commodity pickup location and commodity dropoff location is a vertex. If a commodity is currently in transit by a transport, then it will have a drop off vertex, but not a pickup vertex. 16 | 17 | Each vertex in this set is referred to as a route action. The cluster's route actions are divided into subsets as follows. 18 | 19 | TA = transport start actions 20 | PA = commodity pickup actions 21 | DA = commodity dropoff action 22 | CA = commodity actions = PA + DA 23 | RA = route actions = TA + CA = the cluster 24 | 25 | Each vertex is augmented by a capacity vector. 26 | 27 | In this document, a transport start action is used synonymously with "a transport" and a commodity (pickup or dropoff) action is used synonymously with "a commodity". 28 | 29 | ## Route 30 | A route is a partition of the set of route actions for a cluster into disjoint directed paths. This partition follows the following rules. 31 | 32 | 1. Every path must start with a transport action 33 | 2. Every transport action must start its own path 34 | 3. Every commodity pickup action must be in the same path and sequentially before its corresponding dropoff action 35 | 4. Each component of the sum of the capacity vectors up to each vertex along a path must be nonnegative 36 | 37 | ## Variables 38 | 39 | These binary variable sufficiently describe a route as described in the previous section 40 | 41 | x[k1,k2,i], k1 ∈ RA, k2 ∈ RA, i ∈ TA = transport i's path contains an edge from k1 to k2 42 | 43 | ## Parameters 44 | 45 | distances[k1,k2], k1 ∈ RA, k2 ∈ RA = driving distance in meters from k1 to k2 46 | durations[k1,k2], k1 ∈ RA, k2 ∈ RA = driving duration in seconds from k1 to k2 47 | request_time[d], d ∈ DA = the time that commodity with dropoff d originally requested transportation 48 | 49 | ## Supplementary Variables 50 | 51 | These variables are not strictly necessary to compute a route, but they are derived from the variables and parameters previously listed and they help in forming complex objective functions 52 | 53 | y[k1,k2,i], k1 ∈ RA, k2 ∈ RA, i ∈ TA = transport i's path contains a subpath from k1 to k2 54 | z[k1,k2,k3], k1 ∈ RA, k2 ∈ RA, k3 ∈ TA = the subpath from a transport to commodity action k3 contains an edge from k1 to k2 55 | distance[i], i ∈ TA = the distance of transport i's path 56 | duration[i], i ∈ TA = the duration of transport i's path 57 | distance[d], d ∈ DA = The distance traveled by the commodity dropped off at d 58 | duration[d], d ∈ DA = The in transit by the commodity dropped off at d 59 | pickup_time[d], d ∈ DA = The time that the commodity dropped off at d will be picked up or 0 if it has already been picked up 60 | dropoff_time[d], d ∈ DA = The time that commodity d dropped off at d will be dropped off 61 | 62 |
63 | 64 | # Objective Function DSL 65 | 66 | Objective functions are the criteria used to optimize routes. Under the hood, Pathfinder uses complex mathematics to determine the optimal route at any given time. However, to use Pathfinder it is not required to understand the underlying model. Instead, objective functions are specified using a Domain Specific Language (DSL). If this seems too complicated, don't fret! The Pathfinder dashboard contains two predefined objective functions that cover common use cases: minimizing distance and minimizing time. 67 | 68 | Note that the "objective functions" described by this document are strictly speaking not objective functions. If you're interested in how Pathfinder transforms this DSL into mathematical expressions, you can read more about the DSL Compiler. 69 | 70 | ## Concepts and Terminology 71 | 72 | An objective function is a function from some variables to a real number and an instruction to either minimize or maximize that number. For Pathfinder, routes are calculated with cluster-granularity. The input to the objective function is the "route" for the cluster for the snapshot in time when it is calculated. There are three parts to a Pathfinder objective function: sense, context and quantity. 73 | 74 | ### Sense 75 | This is the instruction to either minimize or maximize the function. 76 | 77 | ### Context 78 | Since the input to the objective function is all of the routes for transports in the cluster, every objective function will involve iterating over the transports, the commodities or some Cartesian product of those sets. An expression is computed during the iteration and then either a sum, min or max is computed. This is essentially a "foreach loop" from most familiar programming languages. 79 | 80 | For instance, I may want to minimize the maximum distance traveled by any transports. In this case, Pathfinder iterates over the set of transports and evaluates a maximum. "max" is referred to as the "method" and transports is referred to as the "entities". 81 | 82 | Alternatively, I may want to minimize the total difference between commodity wait times. In this case, Pathfinder iterates over the set of all pairs of commodities and evaluates a sum. The method is "sum" and the entities are the Cartesian product of commodities with commodities. 83 | 84 | ### Quantity 85 | This is the value that will be computed for each iteration of the context. It is an algebraic combination of route variables, a few Pathfinder specific keyword quantities and parameters that are configured for your application and passed in via the metadata of transports and commodities. 86 | 87 | The currently supported operations are absolute value, add, subtract, multiply and divide. This list is admittedly limited, however that is due to the need for the expression to be representable by a "linear combination" for Pathfinder's optimizer to function correctly. 88 | 89 | 90 | ## Syntax 91 | 92 | The Pathfinder DSL is a (very small) subset of YAML. Every objective function has the form 93 | 94 | sense: 95 | context: 96 | method: 97 | for: 98 | quantity: 99 | 100 | 101 | 102 | ### Sense 103 | 104 | Sense = min | max 105 | 106 | ### Context 107 | Method = sum | min | max 108 | Entity Dictionary = 109 | : commodity | transport 110 | : commodity | transport 111 | : commodity | transport 112 | 113 | 114 | ### Quantity 115 | Expression = Value | Evaluation 116 | 117 | Evaluation = 118 | : 119 | - Quantity Expression 120 | ... 121 | Value = Constant | . 122 | Constant = | 123 | Property = | 124 | Function = absolute_value | add | subtract | multiply | divide 125 | 126 | #### Global 127 | 128 | - `now` - UTC timestamp when the route is calculated 129 | 130 | #### Transport Keywords 131 | - `distance` - The route length for the transport 132 | - `duration` - The route duration for the transport 133 | 134 | #### Commodity Keywords 135 | - `request_time` - The UTC timestamp for when the commodity was first set to `Waiting` status 136 | - `pickup_time` - The UTC timestamp for when the commodity will be picked up in the route 137 | - `dropoff_time` - The UTC timestamp for when the commodity will be dropped off in the route 138 | - `distance` - The distance that the commodity will travel according to the route 139 | 140 | #### Parameters 141 | 142 | These must be configured via the Pathfinder dashboard and included in the `metadata` for commodity or transports when they are created and updated via the SDKs. If the parameters are not present in the metadata, Pathfinder will make intelligent guesses (MAX\_INT, MIN\_INT, 0) based on your objective function. However, this is strongly discouraged. 143 | 144 | 145 | ## Examples 146 | ##### Minimize total transport distance 147 | - [x] Julia 148 | 149 | @setObjective(model, Min, sum{distance[k1,k2]*x[k1,k2,i],k1=RA,k2=RA,i=TA}) 150 | 151 | - [x] DSL 152 | 153 | sense: min 154 | context: 155 | method: sum 156 | for: 157 | t: transport 158 | quantity: t.distance 159 | 160 | #### Minimize total transport time 161 | - [x] Julia 162 | 163 | @setObjective(model, Min, sum{duration[k1,k2]*x[k1,k2,i],k1=RA,k2=RA,i=TA}) 164 | 165 | - [x] DSL 166 | 167 | sense: min 168 | context: 169 | method: sum 170 | for: 171 | t: transport 172 | quantity: t.duration 173 | 174 | 175 | #### Minimize max transport distance 176 | - [x] Julia 177 | 178 | @defVar(model, _value, Int) 179 | for i in TA 180 | @addConstraint(model, _value >= sum{distance[k1,k2]*x[k1,k2,i], k1=RA, k2=RA}) 181 | end 182 | @setObjective(model, Min, _value) 183 | 184 | - [x] DSL 185 | 186 | sense: min 187 | context: 188 | method: max 189 | for: 190 | t: transport 191 | quantity: t.distance 192 | 193 | #### Minimize max transport route duration 194 | - [x] Julia 195 | 196 | @defVar(model, _value, Int) 197 | for i in TA 198 | @addConstraint(model, _value >= sum{duration[k1,k2]*x[k1,k2,i], k1=RA, k2=RA}) 199 | end 200 | @setObjective(model, Min, _value) 201 | 202 | - [x] DSL 203 | 204 | sense: min 205 | context: 206 | method: max 207 | for: 208 | t: transport 209 | quantity: t.duration 210 | 211 | #### Minimize max time until passenger pickup 212 | - [x] Julia 213 | 214 | @defVar(model, _value, Int) 215 | for i in PA 216 | @addConstraint(model, _value >= sum{duration[k1,k2]*z[k1,k2,i], k1=RA, k2=RA}) 217 | end 218 | @setObjective(model, Min, _value) 219 | 220 | - [x] DSL 221 | 222 | sense: min 223 | context: 224 | method: max 225 | for: 226 | c: commodity 227 | quantity: c.pickup_time 228 | 229 | #### Minimize max fuel used by a transport 230 | - [x] Julia 231 | 232 | @defVar(model, _value, Int) 233 | for i in PA 234 | @addConstraint(model, _value >= sum{distance[k1,k2]*1/mpg[i]*x[k1,k2,i], k1=RA, k2=RA}) 235 | end 236 | @setObjective(model, Min, _value) 237 | 238 | - [x] DSL 239 | 240 | sense: min 241 | context: 242 | method: sum 243 | for: 244 | t: transport 245 | quantity: 246 | divide: 247 | - t.distance 248 | - t.mpg 249 | 250 | #### Minimize total fuel used by transports 251 | - [x] Julia 252 | 253 | mpg = parameters['mpg'] 254 | @setObjective(model, Min, sum{distance[k1,k2]*1/mpg[i]*x[k1,k2,i],k1=RA,k2=RA,i=TA}) 255 | 256 | - [x] DSL 257 | 258 | sense: min 259 | context: 260 | method: sum 261 | for: 262 | t: transport 263 | quantity: 264 | divide: 265 | - t.distance 266 | - t.mpg 267 | 268 | #### Minimize max time until passenger dropoff 269 | - [x] Julia 270 | 271 | @defVar(model, _value, Int) 272 | for i in DA 273 | @addConstraint(model, _value >= sum{duration[k1,k2]*z[k1,k2,i], k1=RA, k2=RA}) 274 | end 275 | @setObjective(model, Min, _value) 276 | 277 | - [x] DSL 278 | 279 | sense: min 280 | context: 281 | - method: max 282 | - for: 283 | c: commodity 284 | quantity: 285 | subtract: 286 | - c.dropoff_time 287 | - now 288 | 289 | 290 | #### Minimize maximum time until dropoff including past wait time 291 | - [x] Julia 292 | 293 | requesttime = parameters['requesttime'] 294 | @defVar(model, _value, Int) 295 | for i in DA 296 | @addConstraint(model, _value >= time - requesttime[i] + sum{duration[k1,k2]*z[k1,k2,i], k1=RA, k2=RA} 297 | end 298 | @setObjective(model, Min, _value) 299 | 300 | - [x] DSL 301 | 302 | sense: min 303 | context: 304 | - method: max 305 | - for: 306 | c: commodity 307 | quantity: 308 | subtract: 309 | - c.dropoff_time 310 | - c.request_time 311 | 312 | #### Minimize time until pickup weighted by customer priority 313 | - [x] Julia 314 | 315 | priority = parameters['priority'] 316 | @setObjective(model, Min, sum{z[k1,k2,k3]*duration[k1,k2]*priority[k3],k1=RA,k2=RA,k3=PA}) 317 | 318 | - [x] DSL 319 | 320 | sense: min 321 | context: 322 | method: sum 323 | for: 324 | c: commodity 325 | quantity: 326 | multiply: 327 | - subtract: 328 | - c.pickup_time 329 | - now 330 | - c.priority 331 | 332 | #### Minimize total time from now until drop off weighted by customer priority 333 | - [x] Julia 334 | 335 | priority = parameters['priority'] 336 | @setObjective(model, Min, sum{z[k1,k2,k3]*duration[k1,k2]*priority[k3],k1=RA,k2=RA,k3=DA}) 337 | 338 | - [x] DSL 339 | 340 | sense: min 341 | context: 342 | method: sum 343 | for: 344 | c: commodity 345 | quantity: 346 | multiply: 347 | - substract: 348 | - c.dropoff_time 349 | - now 350 | - c.priority 351 | 352 | #### Minimize maximum distance traveled by commodity 353 | 354 | - [ ] Julia 355 | 356 | @defVar(model, _value, Int) 357 | for i in DA 358 | ??? 359 | end 360 | @setObjective(model, Min, _value) 361 | 362 | - [x] DSL 363 | 364 | sense: min 365 | context: 366 | method: max 367 | for: 368 | c: commodity 369 | quantity: c.distance 370 | 371 | 372 | #### Minimize maximum difference between passenger total wait times 373 | 374 | - [ ] Julia 375 | 376 | @defVar(model, _value, Int) 377 | for c1 in CA 378 | for c2 in CA 379 | ??? 380 | end 381 | end 382 | @setObjective(model, Min, _value) 383 | 384 | - [x] DSL 385 | 386 | sense: min 387 | context: 388 | method: max 389 | for: 390 | c1: commodity 391 | c2: commodity 392 | quantity: 393 | absolute_value: 394 | subtract: 395 | - subtract: 396 | - c1.dropoff_time 397 | - c1.request_time 398 | - subtract: 399 | - c2.dropoff_time 400 | - c2.dropoff_time 401 | 402 | #### Minimize sum of differences between passenger total wait times 403 | 404 | - [x] Julia - This one I have tested extensively. It is a good example of how quantity is expanded. 405 | 406 | @defVar(model, _value, Int) 407 | @defVar(model, _tmp1[DA,DA], Int) 408 | @defVar(model, _tmp2[DA,DA], Int) 409 | @defVar(model, _tmp3[DA,DA], Int) 410 | @defVar(model, _tmp4[DA,DA], Int) 411 | @defVar(model, pos_tmp4[DA,DA] >= 0, Int) 412 | @defVar(model, neg_tmp4[DA,DA] >= 0, Int) 413 | for c1 in DA 414 | for c2 in DA 415 | @addConstraint(model, _tmp1[c1,c2] == dropoff_time[c1] - parameters["request_time"][c1]) 416 | @addConstraint(model, _tmp2[c1,c2] == dropoff_time[c2] - parameters["request_time"][c2]) 417 | @addConstraint(model, _tmp3[c1,c2] == _tmp1[c1,c2] - _tmp2[c1,c2]) 418 | @addConstraint(model, _tmp4[c1,c2] == pos_tmp4[c1,c2] + neg_tmp4[c1,c2]) 419 | @addConstraint(model, _tmp3[c1,c2] == pos_tmp4[c1,c2] - neg_tmp4[c1,c2]) 420 | end 421 | end 422 | @addConstraint(model, _value == sum{_tmp4[c1,c2],c1=DA,c2=DA}) 423 | @setObjective(model, Min, _value) 424 | 425 | - [x] DSL 426 | 427 | sense: min 428 | context: 429 | method: sum 430 | for: 431 | c1: commodity 432 | c2: commodity 433 | quantity: 434 | absolute_value: 435 | - subtract: 436 | - subtract: 437 | - c1.dropoff_time 438 | - c1.request_time 439 | - subtract: 440 | - c2.dropoff_time 441 | - c2.request_time 442 | -------------------------------------------------------------------------------- /linearprogramming/docs/request.json: -------------------------------------------------------------------------------- 1 | { 2 | "vehicles": [ 1, 3, 5 ], 3 | "commodities": { 4 | 0: 2, 5 | 6: 4 6 | }, 7 | "distances": [ 8 | [ 0, 1, 1, 1, 1, 1, 1], 9 | [ 1, 0, 1, 1, 1, 1, 1], 10 | [ 1, 1, 0, 1, 1, 1, 1], 11 | [ 1, 1, 1, 0, 1, 1, 1], 12 | [ 1, 1, 1, 1, 0, 1, 1], 13 | [ 1, 1, 1, 1, 1, 0, 1], 14 | [ 1, 1, 1, 1, 1, 1, 0] 15 | ], 16 | "durations": [ 17 | [ 0, 1, 1, 1, 1, 1, 1], 18 | [ 1, 0, 1, 1, 1, 1, 1], 19 | [ 1, 1, 0, 1, 1, 1, 1], 20 | [ 1, 1, 1, 0, 1, 1, 1], 21 | [ 1, 1, 1, 1, 0, 1, 1], 22 | [ 1, 1, 1, 1, 1, 0, 1], 23 | [ 1, 1, 1, 1, 1, 1, 0] 24 | ], 25 | "capacities": [ 26 | { 27 | 0: 7, 28 | 1: 7, 29 | 3: 7, 30 | 5: 7, 31 | 6: 7 32 | } 33 | ], 34 | "commodityParameters": [ 35 | { 36 | 0: 7, 37 | 6: 7 38 | } 39 | ], 40 | "vehicleParameters" [ 41 | { 42 | 1: 12, 43 | 3: 99, 44 | 5: -10 45 | } 46 | ], 47 | "objective": "Julia math expression" 48 | } 49 | -------------------------------------------------------------------------------- /linearprogramming/docs/response.json: -------------------------------------------------------------------------------- 1 | { 2 | "route": [ 3 | [ 1, 0, 2 ], 4 | [ 3 ], 5 | [ 5, 4, 6 ] 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /linearprogramming/src/PathfinderRouting.jl: -------------------------------------------------------------------------------- 1 | module PathfinderRouting 2 | 3 | include("server.jl") 4 | include("solve.jl") 5 | 6 | end # module 7 | -------------------------------------------------------------------------------- /linearprogramming/src/server.jl: -------------------------------------------------------------------------------- 1 | using HttpServer 2 | using JSON 3 | using Logging 4 | 5 | Logging.configure(level=DEBUG) 6 | 7 | 8 | include("solve.jl") 9 | 10 | function parsetransports(raw) 11 | return raw["transports"] 12 | end 13 | 14 | function parsecommodities(raw) 15 | commodities = raw["commodities"] 16 | return [parse(Int64, p) => commodities[p] for p=keys(commodities)] 17 | end 18 | 19 | function parsecapacities(raw) 20 | capacities = raw["capacities"] 21 | return [[parse(Int64, a) => capacities[c][a] for a=keys(capacities[c])] for c=keys(capacities)] 22 | end 23 | 24 | function parseparameters(raw) 25 | parameters = raw["parameters"] 26 | return [p => [parse(Int64, a) => parameters[p][a] for a=keys(parameters[p])] for p=keys(parameters)] 27 | end 28 | 29 | function parsedistances(raw) 30 | return transpose(hcat(raw["distances"]...)) 31 | end 32 | 33 | function parsedurations(raw) 34 | return transpose(hcat(raw["durations"]...)) 35 | end 36 | 37 | function parseobjective(raw) 38 | if "objective" in keys(raw) 39 | return raw["objective"] 40 | else 41 | return "sum{distances[k1,k2]*x[k1,k2,i],k1=RA,k2=RA,i=VA}" 42 | end 43 | end 44 | 45 | function handle(jsonreq) 46 | transports = parsetransports(jsonreq) 47 | commodities = parsecommodities(jsonreq) 48 | capacities = parsecapacities(jsonreq) 49 | parameters = parseparameters(jsonreq) 50 | distances = parsedistances(jsonreq) 51 | durations = parsedurations(jsonreq) 52 | objective = parseobjective(jsonreq) 53 | return optimize(transports, commodities, distances, durations, capacities, parameters, objective) 54 | end 55 | 56 | function startserver() 57 | http = HttpHandler() do req::Request, res::Response 58 | info("Received route request: ", JSON.parse(bytestring(req.data))) 59 | jsonreq = JSON.parse(bytestring(req.data)) 60 | result = handle(jsonreq) 61 | response = JSON.json(Dict("routes" => result)) 62 | info("Returning response: ", response) 63 | return Response(response) 64 | end 65 | 66 | server = Server(http) 67 | run(server, 2929) 68 | end 69 | -------------------------------------------------------------------------------- /linearprogramming/src/server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 3 | julia -e "include(\"$(echo $DIR)/PathfinderRouting.jl\"); PathfinderRouting.startserver()" 4 | -------------------------------------------------------------------------------- /linearprogramming/src/solve.jl: -------------------------------------------------------------------------------- 1 | using Logging 2 | 3 | original = """ 4 | using JuMP 5 | using Logging 6 | 7 | function routecalculation(transports, commodities, distances, durations, capacities, parameters, nowf) 8 | now = round(Int, nowf) 9 | TA = transports 10 | DA = [p for p=keys(commodities)] 11 | PA = [d for d=values(commodities)] 12 | CA = setdiff(union(PA, DA), TA) 13 | RA = union(PA, DA, TA) 14 | 15 | info("Capacities: ", capacities) 16 | 17 | model = Model() 18 | 19 | @defVar(model, pickup_time[DA]) 20 | @defVar(model, dropoff_time[DA]) 21 | @defVar(model, distance[RA] >= 0, Int) 22 | @defVar(model, duration[RA] >= 0, Int) 23 | 24 | # x[k1,k2,i] = transport i's path contains an edge from k1 to k2 25 | @defVar(model, x[RA,RA,TA], Bin) 26 | 27 | # y[k1,k2,i] = transport i's path contains a subpath from k1 to k2 28 | @defVar(model, y[RA,RA,TA], Bin) 29 | 30 | # z[k1,k2,k3] = the subpath starting at a transport and ending at k3 contains 31 | # an edge from k1 to k2 32 | @defVar(model, z[RA,RA,CA], Bin) 33 | 34 | @defVar(model, r[RA,RA,TA], Int) 35 | @defVar(model, rpos[RA,RA,TA] >= 0, Int) 36 | @defVar(model, rneg[RA,RA,TA] >= 0, Int) 37 | 38 | @defVar(model, q[RA,RA,TA], Int) 39 | @defVar(model, qpos[RA,RA,TA] >= 0, Int) 40 | @defVar(model, qneg[RA,RA,TA] >= 0, Int) 41 | 42 | for i in TA 43 | @addConstraint(model, duration[i] == sum{durations[k1,k2]*x[k1,k2,i],k1=RA,k2=RA}) 44 | @addConstraint(model, distance[i] == sum{distances[k1,k2]*x[k1,k2,i],k1=RA,k2=RA}) 45 | end 46 | 47 | for c in DA 48 | @addConstraint(model, distance[c] == sum{distances[k1,k2]*z[k1,k2,c],k1=RA,k2=RA}) 49 | @addConstraint(model, duration[c] == sum{durations[k1,k2]*z[k1,k2,c],k1=RA,k2=RA}) 50 | end 51 | 52 | for c in capacities 53 | for k2 in CA 54 | for i in TA 55 | # Every route segment obeys constraint limits 56 | @addConstraint(model, sum{c[k1]*y[k1,k2,i], k1=CA} <= c[i]) 57 | end 58 | end 59 | end 60 | 61 | for k1 in RA 62 | for k2 in RA 63 | for k3 in CA 64 | # Definition of z 65 | @addConstraint(model, 2*z[k1,k2,k3] <= sum{x[k1,k2,i]+y[k1,k3,i], i=TA}) 66 | @addConstraint(model, z[k1,k2,k3] >= sum{x[k1,k2,i]+y[k1,k3,i], i=TA} - 1) 67 | end 68 | end 69 | end 70 | 71 | for k1 in RA 72 | # Every node has at most one sucessor. 73 | @addConstraint(model, sum{x[k1,k2,i], k2=RA, i=TA} <= 1) 74 | for k2 in RA 75 | for i in TA 76 | # Definition of r 77 | @addConstraint(model, r[k1,k2,i] == sum{y[k3,k2,i] - y[k3,k1,i], k3=RA} - 1) 78 | @addConstraint(model, r[k1,k2,i] == rpos[k1,k2,i] - rneg[k1,k2,i]) 79 | @addConstraint(model, 1 - x[k1,k2,i] <= rpos[k1,k2,i] + rneg[k1,k2,i]) 80 | # Definition of q 81 | @addConstraint(model, q[k1,k2,i] == x[k1,k2,i] - y[k1,k2,i] - 1) 82 | @addConstraint(model, q[k1,k2,i] == qpos[k1,k2,i] - qneg[k1,k2,i]) 83 | @addConstraint(model, qpos[k1,k2,i] + qneg[k1,k2,i] >= 1) 84 | 85 | # Y includes X 86 | @addConstraint(model, y[k1,k2,i] - x[k1,k2,i] >= 0) 87 | 88 | # Y route implies X route 89 | @addConstraint(model, sum{x[k1,k3,i]+x[k3,k2,i],k3=RA} >= 2*y[k1,k2,i]) 90 | end 91 | end 92 | end 93 | 94 | for k in RA 95 | for i in TA 96 | # A route action cannot occur before itself. 97 | @addConstraint(model, x[k,k,i] == 0) 98 | @addConstraint(model, y[k,k,i] == 0) 99 | end 100 | end 101 | 102 | for d in keys(commodities) 103 | # Commodity pickups are in the same route as their dropoffs. 104 | @addConstraint(model, sum{y[commodities[d],d,i], i=TA} == 1) 105 | if commodities[d] in CA 106 | @addConstraint(model, pickup_time[d] - now == sum{z[k1,k2,commodities[d]]*durations[k1,k2],k1=RA,k2=RA}) 107 | end 108 | @addConstraint(model, dropoff_time[d] - now == sum{z[k1,k2,d]*durations[k1,k2],k1=RA,k2=RA}) 109 | end 110 | 111 | for k in CA 112 | # Every CA has a predecessor. 113 | @addConstraint(model, sum{x[a,k,i], a=RA, i=TA} == 1) 114 | for i in TA 115 | # Flow into and out of a vertex occur in the same route. 116 | @addConstraint(model, sum{x[a,k,i]-x[k,a,i], a=RA} >= 0) 117 | end 118 | end 119 | 120 | for a in RA 121 | for b in CA 122 | for c in CA 123 | for i in TA 124 | @addConstraint(model, y[a,b,i] >= x[a,c,i] + y[c,b,i] - 1) 125 | end 126 | end 127 | end 128 | end 129 | 130 | for k1 in CA 131 | @addConstraint(model, sum{y[i,k1,i], i=TA} == 1) 132 | for k2 in RA 133 | if k1 != k2 134 | @addConstraint(model, sum{y[k1,k2,i] + y[k2,k1,i], i=TA} <= 1) 135 | end 136 | end 137 | end 138 | 139 | 140 | for k1 in RA 141 | for k2 in TA 142 | for i in TA 143 | # A transport start action does not have a predecessor. 144 | @addConstraint(model, x[k1,k2,i] == 0) 145 | if k2 != i 146 | # A transport cannot be in another transport's route. 147 | @addConstraint(model, x[k2, k1, i] == 0) 148 | end 149 | end 150 | end 151 | end 152 | 153 | FUCKTHIS 154 | 155 | status = solve(model) 156 | info("Objective: ", getObjectiveValue(model)) 157 | 158 | solveroutput = getValue(x) 159 | routes = [] 160 | for i in TA 161 | components = Dict() 162 | for k1 in RA 163 | for k2 in RA 164 | if solveroutput[k1,k2,i] > 0.9 165 | components[k1] = k2 166 | end 167 | end 168 | end 169 | position = i 170 | order = [position] 171 | while haskey(components, position) 172 | nextposition = components[position] 173 | delete!(components, position) 174 | position = nextposition 175 | push!(order, position) 176 | end 177 | push!(routes, order) 178 | end 179 | return routes 180 | end 181 | 182 | """ 183 | 184 | function optimize(transports, commodities, distances, durations, capacities, parameters, objective, now = time()) 185 | code = replace(original, "FUCKTHIS", objective) 186 | return include_string(code)(transports, commodities, distances, durations, capacities, parameters, now) 187 | end 188 | -------------------------------------------------------------------------------- /linearprogramming/stress_test/Routing Stress Test Results.md: -------------------------------------------------------------------------------- 1 | # Routing Stress Test Results 2 | 3 | TLDR: It's worse than we thought. 4 | 5 | ## Timing Tests 6 | 7 | All times are in seconds. 8 | 9 | ### n1-highcpu-2 10 | 11 | ||C=1 |C=2 |C=3 |C=4 |C=5 |C=6 | 12 | |---|---|---|---|---|---|---| 13 | |T=1| 3.10 | 2.75 | 5.79 |18.66|69.24|3289.66| 14 | |T=2|3.45|2.69|7.47|79.87|9670.57|| 15 | |T=3|3.45|3.15|3.81|4121.82|>259200|| 16 | |T=4|2.78|3.20|5.14|||| 17 | |T=5|2.78|4.39|540.10|||| 18 | |T=6|3.31|3.77||||| 19 | |T=7|3.48|8.79||||| 20 | |T=8|2.97|14.42||||| 21 | |T=9|4.58|21.84||||| 22 | 23 | ### n1-highcpu-16 24 | 25 | ||C=1 |C=2 |C=3 |C=4 |C=5 |C=6 | 26 | |---|---|---|---|---|---|---| 27 | |T=1|2.47|2.30|4.79|18.48|137.24|| 28 | |T=2|2.23|2.48|7.26|64.60||| 29 | |T=3|2.31|2.63|3.27|||| 30 | |T=4|2.60|2.76|4.63|||| 31 | |T=5|2.46|3.32|524.17|||| 32 | |T=6|2.41|3.33||||| 33 | |T=7|2.51|7.47||||| 34 | |T=8|2.59|12.90||||| 35 | |T=9|3.96|18.28||||| 36 | 37 | ### n1-highmem-2 38 | ||C=1 |C=2 |C=3 |C=4 |C=5 |C=6 | 39 | |---|---|---|---|---|---|---| 40 | |T=1|2.47|2.25|5.63|23.02|168.50|| 41 | |T=2|2.39|2.59|6.82|242.34||| 42 | |T=3|2.54|2.74|3.31|1137.38||| 43 | |T=4|2.55|2.94|4.90|||| 44 | |T=5|2.95|3.49||||| 45 | |T=6|2.44|3.28||||| 46 | |T=7|2.65|7.91||||| 47 | |T=8|2.63|12.96||||| 48 | |T=9|3.95|19.06||||| 49 | 50 | ## CPU vs Memory 51 | 52 | We're definitely CPU-limited. 53 | 54 | ![out.png](out.jpg) 55 | 56 | ## Code Profiling Results 57 | 58 | [Line by line results](https://raw.githubusercontent.com/CSSE497/PathfinderRouting/topic/profiling/stress_test/profile-4-vehicles-3-commodities.txt) 59 | 60 | For a ~5-second request, 1515942/1518016 = 99.86337% of the request was spent inside the solving mechanism. -------------------------------------------------------------------------------- /linearprogramming/stress_test/out.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CSSE497/pathfinder-routing/c234fdfe8eebc2799b39f7071cc0091884f71a26/linearprogramming/stress_test/out.jpg -------------------------------------------------------------------------------- /linearprogramming/stress_test/profile-4-vehicles-3-commodities.txt: -------------------------------------------------------------------------------- 1 | 2 ...4.1.app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 2 | 1518016 REPL.jl; anonymous; line: 92 3 | 1518016 REPL.jl; eval_user_input; line: 62 4 | 1518016 profile.jl; anonymous; line: 16 5 | 1518016 ...rs/adam/Programming/PathfinderRouting/src/server.jl; handle; line: 53 6 | 1433 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; typeinf_ext; (unknown line) 7 | 1433 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; typeinf; (unknown line) 8 | 1433 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; typeinf_uncached; (unknown line) 9 | 111 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_interpret; (unknown line) 10 | 109 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval; (unknown line) 11 | 109 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval_call; (unknown line) 12 | 86 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_call; (unknown line) 13 | 31 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_call; (unknown line) 14 | 31 ....app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_call_gf; (unknown line) 15 | 30 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 16 | 30 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 17 | 30 ...app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 18 | 30 ...app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 19 | 30 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 20 | 30 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 21 | 30 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 22 | 30 ...p/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 23 | 30 ...p/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 24 | 48 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_call_gf; (unknown line) 25 | 36 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 26 | 32 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 27 | 32 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 28 | 4 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 29 | 2 ...app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 30 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 31 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; func_for_method; (unknown line) 32 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; istopfunction; (unknown line) 33 | 3 ....app/Contents/Resources/julia/lib/julia/sys.dylib; next; (unknown line) 34 | 2 ....app/Contents/Resources/julia/lib/julia/sys.dylib; typeinf; (unknown line) 35 | 2 ....app/Contents/Resources/julia/lib/julia/sys.dylib; typeinf; (unknown line) 36 | 2 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; builtin_tfunction; (unknown line) 37 | 2 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; anonymous; (unknown line) 38 | 2 ....app/Contents/Resources/julia/lib/julia/sys.dylib; anonymous; (unknown line) 39 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 40 | 22 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval; (unknown line) 41 | 21 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval_call; (unknown line) 42 | 14 ....app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_call; (unknown line) 43 | 12 ....app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_call_gf; (unknown line) 44 | 8 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 45 | 8 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 46 | 8 ...app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 47 | 6 ...app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 48 | 3 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 49 | 1 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 50 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; next; (unknown line) 51 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval_constant; (unknown line) 52 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; builtin_tfunction; (unknown line) 53 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; anonymous; (unknown line) 54 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; anonymous; (unknown line) 55 | 5 ....app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval; (unknown line) 56 | 5 ....app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval_call; (unknown line) 57 | 5 ....app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_call; (unknown line) 58 | 4 ....app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_call_gf; (unknown line) 59 | 4 ...app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 60 | 3 ...app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 61 | 3 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 62 | 3 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 63 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval_constant; (unknown line) 64 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 65 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; unsafe_getindex; (unknown line) 66 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval_symbol; (unknown line) 67 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 68 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; done; (unknown line) 69 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; getfield_elim_pass; (unknown line) 70 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; getfield_elim_pass; (unknown line) 71 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 72 | 129 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; inlining_pass; (unknown line) 73 | 129 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; inlining_pass; (unknown line) 74 | 9 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; inlineable; (unknown line) 75 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 76 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 77 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 78 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 79 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 80 | 2 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; ast_localvars; (unknown line) 81 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; inline_worthy; (unknown line) 82 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_more; (unknown line) 83 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_more; (unknown line) 84 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_more; (unknown line) 85 | 3 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; unique_name; (unknown line) 86 | 3 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; contains_is1; (unknown line) 87 | 117 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; inlining_pass; (unknown line) 88 | 53 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; inlineable; (unknown line) 89 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; ==; (unknown line) 90 | 12 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 91 | 12 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 92 | 12 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 93 | 8 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 94 | 7 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 95 | 7 ...app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 96 | 7 ...app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 97 | 7 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 98 | 7 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 99 | 20 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; ast_localvars; (unknown line) 100 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; effect_free; (unknown line) 101 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; effect_free; (unknown line) 102 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; effect_free; (unknown line) 103 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; effect_free; (unknown line) 104 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; effect_free; (unknown line) 105 | 1 ...app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 106 | 2 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; filter; (unknown line) 107 | 2 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; anonymous; (unknown line) 108 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; inline_worthy; (unknown line) 109 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_more; (unknown line) 110 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_more; (unknown line) 111 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_more; (unknown line) 112 | 3 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; istopfunction; (unknown line) 113 | 7 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; unique_name; (unknown line) 114 | 7 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; contains_is1; (unknown line) 115 | 59 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; inlining_pass; (unknown line) 116 | 48 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; inlineable; (unknown line) 117 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; _methods; (unknown line) 118 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 119 | 13 ....app/Contents/Resources/julia/lib/julia/sys.dylib; ast_localvars; (unknown line) 120 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; effect_free; (unknown line) 121 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; effect_free; (unknown line) 122 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; effect_free; (unknown line) 123 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call_p; (unknown line) 124 | 1 ...app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 125 | 21 ....app/Contents/Resources/julia/lib/julia/sys.dylib; filter; (unknown line) 126 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; typeinf; (unknown line) 127 | 7 ....app/Contents/Resources/julia/lib/julia/sys.dylib; unique_name; (unknown line) 128 | 7 ....app/Contents/Resources/julia/lib/julia/sys.dylib; contains_is1; (unknown line) 129 | 8 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; inlining_pass; (unknown line) 130 | 6 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; inlineable; (unknown line) 131 | 5 ....app/Contents/Resources/julia/lib/julia/sys.dylib; ast_localvars; (unknown line) 132 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 133 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; unique_name; (unknown line) 134 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; contains_is1; (unknown line) 135 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 136 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 137 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 138 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; prepend!; (unknown line) 139 | 122 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; stchanged; (unknown line) 140 | 9 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 141 | 38 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; schanged; (unknown line) 142 | 17 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; issubstate; (unknown line) 143 | 411 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; stupdate; (unknown line) 144 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; call; (unknown line) 145 | 5 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; copy; (unknown line) 146 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; sizeof; (unknown line) 147 | 12 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 148 | 80 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; schanged; (unknown line) 149 | 30 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; issubstate; (unknown line) 150 | 5 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; setindex!; (unknown line) 151 | 6 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; smerge; (unknown line) 152 | 98 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; stupdate; (unknown line) 153 | 8 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 154 | 22 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; setindex!; (unknown line) 155 | 641 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; tuple_elim_pass; (unknown line) 156 | 3 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; find_sa_vars; (unknown line) 157 | 3 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; contains_is1; (unknown line) 158 | 221 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_outside_getfield; (unknown line) 159 | 209 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_outside_getfield; (unknown line) 160 | 9 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 161 | 6 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 162 | 178 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_outside_getfield; (unknown line) 163 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; exprtype; (unknown line) 164 | 55 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 165 | 30 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 166 | 7 ....app/Contents/Resources/julia/lib/julia/sys.dylib; is_global; (unknown line) 167 | 7 ....app/Contents/Resources/julia/lib/julia/sys.dylib; contains_is; (unknown line) 168 | 4 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconst; (unknown line) 169 | 80 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_outside_getfield; (unknown line) 170 | 16 ....app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 171 | 9 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 172 | 2 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconst; (unknown line) 173 | 52 ....app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_outside_getfield; (unknown line) 174 | 6 ....app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 175 | 3 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 176 | 31 ....app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_outside_getfield; (unknown line) 177 | 10 ....app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 178 | 4 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 179 | 18 ....app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_outside_getfield; (unknown line) 180 | 7 ....app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 181 | 5 ...app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 182 | 7 ....app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_outside_getfield; (unknown line) 183 | 6 ...app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_outside_getfield; (unknown line) 184 | 3 ...app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 185 | 1 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 186 | 1 ...pp/Contents/Resources/julia/lib/julia/sys.dylib; isconst; (unknown line) 187 | 1 ...app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_outside_getfield; (unknown line) 188 | 2 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; symequal; (unknown line) 189 | 54 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; remove_redundant_temp_vars; (unknown line) 190 | 20 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; delete_var!; (unknown line) 191 | 20 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; filter!; (unknown line) 192 | 20 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; anonymous; (unknown line) 193 | 19 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; is_var_assigned; (unknown line) 194 | 5 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; next; (unknown line) 195 | 11 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; mapreduce_sc_impl; (unknown line) 196 | 11 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; anonymous; (unknown line) 197 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_undef; (unknown line) 198 | 1 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_more; (unknown line) 199 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; occurs_more; (unknown line) 200 | 3 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; sym_replace; (unknown line) 201 | 2 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; sym_replace; (unknown line) 202 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; sym_replace; (unknown line) 203 | 361 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; replace_getfield!; (unknown line) 204 | 4 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 205 | 3 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 206 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; next; (unknown line) 207 | 320 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; replace_getfield!; (unknown line) 208 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 209 | 29 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 210 | 19 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 211 | 6 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; is_global; (unknown line) 212 | 6 ....app/Contents/Resources/julia/lib/julia/sys.dylib; contains_is; (unknown line) 213 | 2 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; isconst; (unknown line) 214 | 222 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; replace_getfield!; (unknown line) 215 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; !; (unknown line) 216 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; colon; (unknown line) 217 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; getindex; (unknown line) 218 | 11 ....app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 219 | 5 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 220 | 100 ....app/Contents/Resources/julia/lib/julia/sys.dylib; replace_getfield!; (unknown line) 221 | 9 ....app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 222 | 7 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 223 | 3 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconst; (unknown line) 224 | 65 ....app/Contents/Resources/julia/lib/julia/sys.dylib; replace_getfield!; (unknown line) 225 | 6 ....app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 226 | 4 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 227 | 2 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconst; (unknown line) 228 | 48 ....app/Contents/Resources/julia/lib/julia/sys.dylib; replace_getfield!; (unknown line) 229 | 8 ....app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 230 | 7 ....app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 231 | 35 ....app/Contents/Resources/julia/lib/julia/sys.dylib; replace_getfield!; (unknown line) 232 | 3 ...app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 233 | 2 ...app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 234 | 1 ...app/Contents/Resources/julia/lib/julia/sys.dylib; isconst; (unknown line) 235 | 11 ...app/Contents/Resources/julia/lib/julia/sys.dylib; replace_getfield!; (unknown line) 236 | 2 ...app/Contents/Resources/julia/lib/julia/sys.dylib; is_known_call; (unknown line) 237 | 1 ...app/Contents/Resources/julia/lib/julia/sys.dylib; isconstantfunc; (unknown line) 238 | 2 ...app/Contents/Resources/julia/lib/julia/sys.dylib; replace_getfield!; (unknown line) 239 | 3 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; type_annotate; (unknown line) 240 | 2 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; eval_annotate; (unknown line) 241 | 2 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; eval_annotate; (unknown line) 242 | 2 ....1.app/Contents/Resources/julia/lib/julia/sys.dylib; eval_annotate; (unknown line) 243 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; contains_is; (unknown line) 244 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; eval_annotate; (unknown line) 245 | 1 ...1.app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval; (unknown line) 246 | 1 ....app/Contents/Resources/julia/lib/julia/sys.dylib; abstract_eval_symbol; (unknown line) 247 | 2 /Users/adam/.julia/v0.4/JuMP/src/macros.jl; routecalculation; line: 118 248 | 1 /Users/adam/.julia/v0.4/JuMP/src/JuMP.jl; call; line: 319 249 | 1 array.jl; push!; line: 433 250 | 1 dict.jl; setindex!; line: 649 251 | 1 dict.jl; _setindex!; line: 632 252 | 1 dict.jl; rehash!; line: 503 253 | 1 /Users/adam/.julia/v0.4/JuMP/src/macros.jl; routecalculation; line: 318 254 | 1 array.jl; getindex; line: 165 255 | 2 /Users/adam/.julia/v0.4/JuMP/src/macros.jl; routecalculation; line: 319 256 | 2 /Users/adam/.julia/v0.4/JuMP/src/JuMPContainer.jl; getindex; line: 52 257 | 1 dict.jl; ht_keyindex; line: 567 258 | 1 /Users/adam/.julia/v0.4/JuMP/src/macros.jl; routecalculation; line: 320 259 | 1 /Users/adam/.julia/v0.4/JuMP/src/affexpr.jl; addConstraint; line: 175 260 | 10 /Users/adam/.julia/v0.4/JuMP/src/parseExpr_staged.jl; routecalculation; line: 341 261 | 9 /Users/adam/.julia/v0.4/JuMP/src/JuMPContainer.jl; getindex; line: 52 262 | 1 dict.jl; ht_keyindex; line: 560 263 | 315 loading.jl; include_string; line: 272 264 | 3 /Users/adam/.julia/v0.4/JuMP/src/macros.jl; anonymous; line: 273 265 | 2 array.jl; collect; line: 250 266 | 1 /Users/adam/.julia/v0.4/JuMP/src/macros.jl; anonymous; line: 309 267 | 1 /Users/adam/.julia/v0.4/JuMP/src/macros.jl; anonymous; line: 311 268 | 1 /Users/adam/.julia/v0.4/JuMP/src/parseExpr_staged.jl; parseExpr; line: 479 269 | 1 abstractarray.jl; cat_t; line: 869 270 | 1515942 string; routecalculation; line: 171 271 | 3 /Users/adam/.julia/v0.4/JuMP/src/solvers.jl; solve; line: 81 272 | 1 /Users/adam/.julia/v0.4/JuMP/src/solvers.jl; buildInternalModel; line: 250 273 | 1 /Users/adam/.julia/v0.4/Cbc/src/CbcSolverInterface.jl; LinearQuadraticModel; line: 54 274 | 1 /Users/adam/.julia/v0.4/Cbc/src/CbcSolverInterface.jl; CbcMathProgModel; line: 41 275 | 2 /Users/adam/.julia/v0.4/JuMP/src/solvers.jl; buildInternalModel; line: 252 276 | 1 /Users/adam/.julia/v0.4/JuMP/src/solvers.jl; prepConstrMatrix; line: 455 277 | 1 /Users/adam/.julia/v0.4/JuMP/src/solvers.jl; prepConstrMatrix; line: 460 278 | 1 sparse/csparse.jl; sparse; line: 74 279 | 1515939 /Users/adam/.julia/v0.4/JuMP/src/solvers.jl; solve; line: 88 280 | 1515939 ...rs/adam/.julia/v0.4/Cbc/src/CbcSolverInterface.jl; optimize!; line: 137 281 | 1 string; routecalculation; line: 180 282 | 1 /Users/adam/.julia/v0.4/JuMP/src/JuMPContainer.jl; getindex; line: 52 283 | -------------------------------------------------------------------------------- /linearprogramming/stress_test/tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import requests 4 | import time 5 | 6 | distance_matrix = [ 7 | [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], 8 | [ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], 9 | [ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], 10 | [ 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 ], 11 | [ 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 ], 12 | [ 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 ], 13 | [ 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 ], 14 | [ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 ], 15 | [ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 ], 16 | [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1 ], 17 | [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 ], 18 | [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1 ], 19 | [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 ] 20 | ] 21 | 22 | def data(t, c): 23 | if t + 2*c > len(distance_matrix): 24 | raise Exception 25 | transports = range(1, t + 1) 26 | commodities = { x: x + c for x in range(t + 1, t + c + 1) } 27 | return { 28 | 'vehicles': transports, 29 | 'commodities': commodities, 30 | 'durations': distance_matrix, 31 | 'distances': distance_matrix, 32 | 'capacities': { 33 | 'capacity': dict({t: 1 for t in transports}, **dict({commodities[d]: 1 for d in commodities}, **{d: -1 for d in commodities})) 34 | }, 35 | 'parameters': { 36 | }, 37 | 'objective': """ 38 | @setObjective(model, Min, sum{distance[i],i=TA}) 39 | """ 40 | } 41 | 42 | def time_request(data): 43 | start = time.time() 44 | r = requests.post('http://routing.thepathfinder.xyz', json=data) 45 | print r.status_code 46 | return time.time() - start 47 | 48 | if __name__ == '__main__': 49 | for t in range(1, len(distance_matrix) - 1): 50 | for c in range(1, (len(distance_matrix) - t) / 2 + 1): 51 | print "Time for {} transports and {} commodities".format(t, c) 52 | print time_request(data(t, c)) 53 | -------------------------------------------------------------------------------- /linearprogramming/test/runtests.jl: -------------------------------------------------------------------------------- 1 | using Base.Test 2 | 3 | tests = [ "solve" ] 4 | 5 | print_with_color(:blue, "Running tests:\n") 6 | 7 | for t in tests 8 | test_fn = "$t.jl" 9 | print_with_color(:green, "* $test_fn\n") 10 | include(joinpath(pwd(), test_fn)) 11 | end 12 | -------------------------------------------------------------------------------- /linearprogramming/test/solve.jl: -------------------------------------------------------------------------------- 1 | using Base.Test 2 | using PathfinderRouting 3 | 4 | ShortestDistance = "@setObjective(model, Min, sum{distances[k1,k2]*x[k1,k2,i],k1=RA,k2=RA,i=TA})" 5 | 6 | # Single optimal solution. 7 | 8 | transports = [ 1, 3, 5 ] 9 | commodities = Dict(2 => 7, 6 => 4) 10 | distances = [] 11 | push!(distances, [0,9,0,9,0,9,9]) 12 | push!(distances, [9,0,9,1,9,9,9]) 13 | push!(distances, [0,9,0,9,0,9,1]) 14 | push!(distances, [9,9,9,0,9,1,9]) 15 | push!(distances, [0,9,0,9,0,9,9]) 16 | push!(distances, [9,9,9,9,9,0,9]) 17 | push!(distances, [9,1,9,9,9,9,0]) 18 | capacities = [Dict{Int64,Any}(1 => 1, 2 => -1, 3 => 1, 4 => 1, 5 => 1, 6 => -1, 7 => 1)] 19 | parameters = Dict() 20 | 21 | expected = [] 22 | push!(expected, [1]) 23 | push!(expected, [3,7,2,4,6]) 24 | push!(expected, [5]) 25 | 26 | route = PathfinderRouting.optimize(transports, commodities, transpose(hcat(distances...)), transpose(hcat(distances...)), capacities, parameters, ShortestDistance) 27 | 28 | @test route == expected 29 | 30 | # Optimal solution is constrained by capacity. 31 | 32 | transports = [ 1, 3, 5 ] 33 | commodities = Dict(2 => 7, 6 => 4) 34 | distances = [] 35 | push!(distances, [0,9,0,9,0,9,9]) 36 | push!(distances, [9,0,9,8,9,9,9]) 37 | push!(distances, [0,9,0,9,0,9,1]) 38 | push!(distances, [9,8,9,0,9,1,9]) 39 | push!(distances, [0,1,0,9,0,9,9]) 40 | push!(distances, [9,9,9,9,9,0,9]) 41 | push!(distances, [9,9,9,1,9,9,0]) 42 | capacities = [Dict{Int64,Any}(1 => 1, 2 => -1, 3 => 1, 4 => 1, 5 => 1, 6 => -1, 7 => 1)] 43 | parameters = Dict() 44 | 45 | expected = [] 46 | push!(expected, [1]) 47 | push!(expected, [3,7,2,4,6]) 48 | push!(expected, [5]) 49 | 50 | route = PathfinderRouting.optimize(transports, commodities, transpose(hcat(distances...)), transpose(hcat(distances...)), capacities, parameters, ShortestDistance) 51 | 52 | @test route == expected 53 | 54 | 55 | # Maximize distance traveled by vehicle 5. 56 | 57 | transports = [ 1, 3, 5 ] 58 | commodities = Dict(2 => 7, 6 => 4) 59 | distances = [] 60 | push!(distances, [1,1,1,1,1,1,1]) 61 | push!(distances, [1,1,1,9,1,1,1]) 62 | push!(distances, [1,1,1,1,1,1,9]) 63 | push!(distances, [1,1,1,1,1,9,1]) 64 | push!(distances, [1,1,1,1,1,1,9]) 65 | push!(distances, [1,1,1,1,1,1,5]) 66 | push!(distances, [1,9,1,1,1,1,1]) 67 | capacities = [Dict{Int64,Any}(1 => 1, 2 => -1, 3 => 1, 4 => 1, 5 => 1, 6 => -1, 7 => 1)] 68 | parameters = Dict() 69 | objective = "@setObjective(model, Min, -1*sum{x[k1,k2,5]*distances[k1,k2], k1=RA, k2=RA})" 70 | 71 | expected = [] 72 | push!(expected, [1]) 73 | push!(expected, [3]) 74 | push!(expected, [5,7,2,4,6]) 75 | 76 | route = PathfinderRouting.optimize(transports, commodities, transpose(hcat(distances...)), transpose(hcat(distances...)), capacities, parameters, objective) 77 | 78 | @test route == expected 79 | 80 | # Vehicle 5 starts with a commodity in route. 81 | 82 | transports = [ 1, 3, 5 ] 83 | commodities = Dict(2 => 5, 6 => 4) 84 | distances = [] 85 | push!(distances, [0,9,0,9,0,9]) 86 | push!(distances, [9,0,9,9,9,9]) 87 | push!(distances, [0,9,0,1,0,9]) 88 | push!(distances, [9,9,9,0,9,1]) 89 | push!(distances, [0,99,0,9,0,9]) 90 | push!(distances, [9,9,9,9,9,0]) 91 | capacities = [Dict{Int64,Any}(1 => 1, 2 => -1, 3 => 1, 4 => 1, 5 => 0, 6 => -1)] 92 | parameters = Dict() 93 | 94 | expected = [] 95 | push!(expected, [1]) 96 | push!(expected, [3,4,6]) 97 | push!(expected, [5,2]) 98 | 99 | route = PathfinderRouting.optimize(transports, commodities, transpose(hcat(distances...)), transpose(hcat(distances...)), capacities, parameters, ShortestDistance) 100 | 101 | @test route == expected 102 | 103 | # Complex DSL output. 104 | 105 | transports = [ 1, 2 ] 106 | commodities = Dict(4 => 3, 6 => 5) 107 | distances = [] 108 | push!(distances, [0,1,1,1,1,1]) 109 | push!(distances, [1,0,1,1,1,1]) 110 | push!(distances, [1,1,0,1,1,1]) 111 | push!(distances, [1,1,1,0,9,1]) 112 | push!(distances, [1,1,1,9,0,1]) 113 | push!(distances, [1,1,1,1,1,0]) 114 | capacities = [] 115 | push!(capacities, Dict(1 => 2, 2 => 1, 3 => 1, 4 => -1, 5 => 2, 6 => -1)) 116 | parameters = Dict("request_time" => Dict(1 => 0, 2 => 0, 3 => -10, 4 => -10, 5 => 0, 6 => 0)) 117 | 118 | objective = """ 119 | @defVar(model, _value, Int) 120 | @defVar(model, _tmp1[DA,DA], Int) 121 | @defVar(model, _tmp2[DA,DA], Int) 122 | @defVar(model, _tmp3[DA,DA], Int) 123 | @defVar(model, _tmp4[DA,DA], Int) 124 | @defVar(model, pos_tmp4[DA,DA] >= 0, Int) 125 | @defVar(model, neg_tmp4[DA,DA] >= 0, Int) 126 | for c1 in DA 127 | for c2 in DA 128 | @addConstraint(model, _tmp1[c1,c2] == dropoff_time[c1] - parameters["request_time"][c1]) 129 | @addConstraint(model, _tmp2[c1,c2] == dropoff_time[c2] - parameters["request_time"][c2]) 130 | @addConstraint(model, _tmp3[c1,c2] == _tmp1[c1,c2] - _tmp2[c1,c2]) 131 | @addConstraint(model, _tmp4[c1,c2] == pos_tmp4[c1,c2] + neg_tmp4[c1,c2]) 132 | @addConstraint(model, _tmp3[c1,c2] == pos_tmp4[c1,c2] - neg_tmp4[c1,c2]) 133 | end 134 | end 135 | @addConstraint(model, _value == sum{_tmp4[c1,c2],c1=DA,c2=DA}) 136 | @setObjective(model, Min, _value) 137 | """ 138 | 139 | expected = [] 140 | push!(expected, [1, 3, 4, 5, 6]) 141 | push!(expected, [2]) 142 | 143 | route = PathfinderRouting.optimize(transports, commodities, transpose(hcat(distances...)), transpose(hcat(distances...)), capacities, parameters, objective, 0) 144 | 145 | @test route == expected 146 | -------------------------------------------------------------------------------- /linearprogramming/util/min_sum_diff_wait.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import requests 4 | 5 | def request_route(route_url): 6 | data = { 7 | 'vehicles': [ 1, 2 ], 8 | 'commodities': { 9 | 4: 3, 10 | 6: 5 11 | }, 12 | 'durations': [ 13 | [ 0, 1, 1, 1, 1, 1 ], 14 | [ 1, 0, 1, 1, 1, 1 ], 15 | [ 1, 1, 0, 1, 1, 1 ], 16 | [ 1, 1, 1, 0, 9, 1 ], 17 | [ 1, 1, 1, 9, 0, 1 ], 18 | [ 1, 1, 1, 1, 1, 0 ], 19 | ], 20 | 'distances': [ 21 | [ 0, 9, 0, 9, 0, 9 ], 22 | [ 9, 0, 9, 9, 9, 9 ], 23 | [ 0, 9, 0, 9, 0, 9 ], 24 | [ 9, 9, 9, 0, 9, 1 ], 25 | [ 0, 99, 0, 9, 0, 9 ], 26 | [ 9, 9, 9, 9, 9, 0 ], 27 | ], 28 | 'capacities': { 29 | 'capacity': { 30 | 1: 2, 31 | 2: 1, 32 | 3: 1, 33 | 4: -1, 34 | 5: 2, 35 | 6: -1 36 | } 37 | }, 38 | 'parameters': { 39 | 'request_time': { 40 | 1: 0, 41 | 2: 0, 42 | 3: -10, 43 | 4: -10, 44 | 5: 0, 45 | 6: 0 46 | } 47 | }, 48 | 'objective': """ 49 | @defVar(model, _value, Int) 50 | @defVar(model, _tmp1[DA,DA], Int) 51 | @defVar(model, _tmp2[DA,DA], Int) 52 | @defVar(model, _tmp3[DA,DA], Int) 53 | @defVar(model, _tmp4[DA,DA], Int) 54 | @defVar(model, pos_tmp4[DA,DA] >= 0, Int) 55 | @defVar(model, neg_tmp4[DA,DA] >= 0, Int) 56 | for c1 in DA 57 | for c2 in DA 58 | @addConstraint(model, _tmp1[c1,c2] == dropoff_time[c1] - parameters["request_time"][c1]) 59 | @addConstraint(model, _tmp2[c1,c2] == dropoff_time[c2] - parameters["request_time"][c2]) 60 | @addConstraint(model, _tmp3[c1,c2] == _tmp1[c1,c2] - _tmp2[c1,c2]) 61 | @addConstraint(model, _tmp4[c1,c2] == pos_tmp4[c1,c2] + neg_tmp4[c1,c2]) 62 | @addConstraint(model, _tmp3[c1,c2] == pos_tmp4[c1,c2] - neg_tmp4[c1,c2]) 63 | end 64 | end 65 | @addConstraint(model, _value == sum{_tmp4[c1,c2],c1=DA,c2=DA}) 66 | @setObjective(model, Min, _value) 67 | """ 68 | } 69 | r = requests.post(route_url, json=data) 70 | print 'Status code: ' + str(r.status_code) 71 | print 'Response json: ' + str(r.json()) 72 | 73 | 74 | if __name__ == '__main__': 75 | request_route('http://localhost:2929') 76 | -------------------------------------------------------------------------------- /linearprogramming/util/sample_request.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import requests 4 | 5 | def request_route(route_url): 6 | data = { 7 | 'vehicles': [ 1, 3, 5 ], 8 | 'commodities': { 9 | 2: 5, 10 | 6: 4 11 | }, 12 | 'durations': [ 13 | [ 0, 1, 1, 1, 1, 1 ], 14 | [ 1, 0, 1, 1, 1, 1 ], 15 | [ 1, 1, 0, 1, 1, 1 ], 16 | [ 1, 1, 1, 0, 1, 1 ], 17 | [ 1, 1, 1, 1, 0, 1 ], 18 | [ 1, 1, 1, 1, 1, 0 ], 19 | ], 20 | 'distances': [ 21 | [ 0, 9, 0, 9, 0, 9 ], 22 | [ 9, 0, 9, 9, 9, 9 ], 23 | [ 0, 9, 0, 9, 0, 9 ], 24 | [ 9, 9, 9, 0, 9, 1 ], 25 | [ 0, 99, 0, 9, 0, 9 ], 26 | [ 9, 9, 9, 9, 9, 0 ], 27 | ], 28 | 'capacities': { 29 | 'capacity': { 30 | 1: 1, 31 | 2: -1, 32 | 3: 1, 33 | 4: 1, 34 | 5: 0, 35 | 6: -1 36 | } 37 | }, 38 | 'parameters': { 39 | 'mpg': { 40 | 1: 10 41 | } 42 | }, 43 | 'objective': """ 44 | @setObjective(model, Min, sum{distance[i],i=TA}) 45 | """ 46 | } 47 | r = requests.post(route_url, json=data) 48 | print dir(r) 49 | print r.text 50 | print 'Status code: ' + str(r.status_code) 51 | print 'Response json: ' + str(r.json()) 52 | 53 | 54 | if __name__ == '__main__': 55 | request_route('http://routing.thepathfinder.xyz') 56 | -------------------------------------------------------------------------------- /masterrouter/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'httparty' 4 | gem 'sinatra' 5 | gem 'sinatra-contrib' 6 | -------------------------------------------------------------------------------- /masterrouter/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | backports (3.6.8) 5 | httparty (0.13.7) 6 | json (~> 1.8) 7 | multi_xml (>= 0.5.2) 8 | json (1.8.3) 9 | multi_json (1.11.2) 10 | multi_xml (0.5.5) 11 | rack (1.6.4) 12 | rack-protection (1.5.3) 13 | rack 14 | rack-test (0.6.3) 15 | rack (>= 1.0) 16 | sinatra (1.4.7) 17 | rack (~> 1.5) 18 | rack-protection (~> 1.4) 19 | tilt (>= 1.3, < 3) 20 | sinatra-contrib (1.4.7) 21 | backports (>= 2.0) 22 | multi_json 23 | rack-protection 24 | rack-test 25 | sinatra (~> 1.4.0) 26 | tilt (>= 1.3, < 3) 27 | tilt (2.0.2) 28 | 29 | PLATFORMS 30 | ruby 31 | 32 | DEPENDENCIES 33 | httparty 34 | sinatra 35 | sinatra-contrib 36 | 37 | BUNDLED WITH 38 | 1.10.6 39 | -------------------------------------------------------------------------------- /masterrouter/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Adam Michael 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /masterrouter/README.md: -------------------------------------------------------------------------------- 1 | # Routing Master 2 | 3 | We tried several approaches to optimize routes: 4 | - Linear Programming 5 | - A\* Heuristics 6 | - Simulated Annealing 7 | 8 | In the end, each approach has it's pros and its cons. And since Google Compute 9 | Engine is fairly cheap, we run all of them simultaneously. This server is 10 | responsible for selecting the best of the best routes. 11 | 12 | Install dependencies with `bundle install`. Run with `rackup`. 13 | -------------------------------------------------------------------------------- /masterrouter/app.rb: -------------------------------------------------------------------------------- 1 | require 'httparty' 2 | require 'json' 3 | require 'sinatra/base' 4 | require 'sinatra/config_file' 5 | require 'thread' 6 | require 'timeout' 7 | 8 | class MasterRouter < Sinatra::Base 9 | register Sinatra::ConfigFile 10 | 11 | config_file 'config.yml' 12 | 13 | def compute_distance(routes, distances) 14 | total = 0 15 | routes.each do |route| 16 | route.each_cons(2) do |a, b| 17 | if distances[a-1].nil? or distances[a-1][b-1].nil? 18 | puts "Distances does not include #{a}, #{b}" 19 | else 20 | total = total + distances[a-1][b-1] 21 | end 22 | end 23 | end 24 | total 25 | end 26 | 27 | post '/' do 28 | request.body.rewind 29 | request_payload = JSON.parse request.body.read 30 | distances = request_payload['distances'] 31 | puts "Route request received with distances #{distances}" 32 | 33 | threads = [] 34 | puts "Sending work to: #{settings.workers}" 35 | settings.workers.each do |u| 36 | threads << Thread.new { 37 | begin 38 | Thread.current[:output] = HTTParty.post(u, { 39 | :body => request_payload.to_json, 40 | :headers => { 'Content-Type' => 'application/json' }, 41 | :timeout => settings.timeout 42 | }).parsed_response 43 | rescue StandardError => e 44 | puts 'Bad or missing response from worker' 45 | puts e.message 46 | Thread.current[:output] = nil 47 | end 48 | } 49 | end 50 | 51 | best_route = nil 52 | best_distance = nil 53 | threads.each do |t| 54 | t.join 55 | unless t[:output].nil? or t[:output]["routes"].nil? 56 | route = t[:output] 57 | distance = compute_distance(route["routes"], distances) 58 | puts "Got route response: #{route} with distance #{distance}" 59 | if best_distance.nil? or distance < best_distance 60 | best_distance = distance 61 | best_route = route 62 | end 63 | end 64 | end 65 | puts "Distance: #{best_distance.to_s}" 66 | best_route = if best_route.nil? then {routes: []} else best_route end 67 | best_route.to_json 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /masterrouter/config.ru: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | 4 | Bundler.require 5 | 6 | require './app' 7 | run MasterRouter 8 | -------------------------------------------------------------------------------- /masterrouter/config.yml: -------------------------------------------------------------------------------- 1 | timeout: 10 2 | workers: 3 | - http://routing2.thepathfinder.xyz 4 | - http://routing3.thepathfinder.xyz:8080/pathfinder-routing-linear-50000 5 | - http://104.197.35.96 6 | - http://104.197.133.77 7 | - http://104.154.34.234:8080/simulatedannealing 8 | - http://146.148.92.187:8080/simulatedannealing 9 | - http://104.154.68.244:8080/simulatedannealing 10 | - http://104.154.64.183:8080/simulatedannealing 11 | - http://104.197.3.178:8080/simulatedannealing 12 | - http://107.178.223.93:8080/simulatedannealing 13 | - http://104.154.63.101:8080/simulatedannealing 14 | - http://104.197.154.96:8080/simulatedannealing 15 | - http://146.148.74.206:8080/simulatedannealing 16 | - http://104.197.44.142:8080/simulatedannealing 17 | - http://104.154.87.155:8080/simulatedannealing 18 | - http://107.178.218.182:8080/simulatedannealing 19 | -------------------------------------------------------------------------------- /simulatedannealing/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.idea 3 | .gradle 4 | build/ 5 | gradle-app.setting 6 | !gradle-wrapper.jar 7 | .gradletasknamecache 8 | .DS_Store 9 | /*.java 10 | /src/main/flex/*.java 11 | /src/main/java/edu/rosehulman/minijavac/generated 12 | *~ 13 | gradlew.bat 14 | settings.gradle 15 | out/ 16 | classes/ 17 | -------------------------------------------------------------------------------- /simulatedannealing/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Adam Michael 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /simulatedannealing/README.md: -------------------------------------------------------------------------------- 1 | # Pathfinder Routing Server v2 2 | 3 | The first iteration just wasn't fast enough, so it's time for a new approach. 4 | -------------------------------------------------------------------------------- /simulatedannealing/build.gradle: -------------------------------------------------------------------------------- 1 | group 'xyz.thepathfinder.routing' 2 | 3 | apply plugin: 'java' 4 | apply plugin: 'war' 5 | 6 | repositories { 7 | mavenCentral() 8 | maven { 9 | url 'http://repository.jboss.org/nexus/content/groups/public-jboss' 10 | } 11 | } 12 | 13 | dependencies { 14 | compile 'com.sun.jersey:jersey-core:1.19.1' 15 | compile 'com.sun.jersey:jersey-json:1.19.1' 16 | compile 'com.sun.jersey:jersey-server:1.19.1' 17 | compile 'com.sun.jersey:jersey-servlet:1.19.1' 18 | compile 'javax.ws.rs:jsr311-api:1.1.1' 19 | compile 'xyz.thepathfinder:simulatedannealing:0.0.3' 20 | compile 'org.slf4j:slf4j-api:1.7.19' 21 | compile 'org.slf4j:slf4j-simple:1.7.19' 22 | testCompile group: 'junit', name: 'junit', version: '4.11' 23 | } 24 | -------------------------------------------------------------------------------- /simulatedannealing/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CSSE497/pathfinder-routing/c234fdfe8eebc2799b39f7071cc0091884f71a26/simulatedannealing/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /simulatedannealing/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Mar 17 20:48:04 EDT 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip 7 | -------------------------------------------------------------------------------- /simulatedannealing/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/domain/CommodityAction.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | public interface CommodityAction extends RouteAction { 4 | } 5 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/domain/CommodityDropoff.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | public class CommodityDropoff implements CommodityAction { 4 | final CommodityStart start; 5 | final String name; 6 | 7 | public CommodityDropoff(String name, CommodityStart start) { 8 | this.start = start; 9 | this.name = name; 10 | } 11 | 12 | @Override 13 | public String getName() { 14 | return name; 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return getName(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/domain/CommodityPickup.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | public class CommodityPickup implements CommodityStart, CommodityAction { 4 | final String name; 5 | 6 | public CommodityPickup(String name) { 7 | this.name = name; 8 | } 9 | 10 | @Override 11 | public String getName() { 12 | return name; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return getName(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/domain/CommodityStart.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | public interface CommodityStart extends RouteAction { 4 | } 5 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/domain/RouteAction.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | public interface RouteAction { 4 | 5 | String getName(); 6 | } 7 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/domain/Transport.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | public class Transport implements CommodityStart { 4 | final String name; 5 | 6 | public Transport(String name) { 7 | this.name = name; 8 | } 9 | 10 | @Override 11 | public String getName() { 12 | return name; 13 | } 14 | 15 | @Override 16 | public String toString() { 17 | return getName(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/domain/VRPSearchState.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Optional; 9 | import java.util.Random; 10 | import java.util.stream.IntStream; 11 | 12 | import xyz.thepathfinder.simulatedannealing.SearchState; 13 | 14 | import static java.util.stream.Collectors.toList; 15 | import static java.util.stream.Collectors.toMap; 16 | 17 | public class VRPSearchState implements SearchState { 18 | final static int MAX_STEP_TRIES = 5; 19 | final VehicleRoutingProblem problem; 20 | final Map> routes; 21 | final Map>> capacitiesByTransportByIndex; 22 | static final Random random = new Random(); 23 | 24 | VRPSearchState(VehicleRoutingProblem problem, Map> routes) { 25 | this.problem = problem; 26 | this.routes = routes; 27 | capacitiesByTransportByIndex = new HashMap<>(); 28 | } 29 | 30 | public Map> getRoutes() { 31 | return routes; 32 | } 33 | 34 | @Override 35 | public VRPSearchState step() { 36 | for (int attempts = MAX_STEP_TRIES; attempts --> 0; ) { 37 | Optional neighbor = 38 | random.nextBoolean() ? swapBetweenRoutes() : swapWithinRoute(); 39 | if (neighbor.isPresent()) { 40 | return neighbor.get(); 41 | } 42 | } 43 | return this; 44 | } 45 | 46 | // Attempts to swap. Probably fails. 47 | public Optional swapWithinRoute() { 48 | List candidates = routes.keySet().stream() 49 | .filter(this::canSwapWithinRoute) 50 | .filter(this::hasSwapCandidates) 51 | .collect(toList()); 52 | if (candidates.isEmpty()) { 53 | return Optional.empty(); 54 | } 55 | Transport selectedTransport = candidates.get(random.nextInt(candidates.size())); 56 | List route = routes.get(selectedTransport); 57 | List> capacities = capacitiesByIndex(selectedTransport); 58 | 59 | // Randomly select a pair of adjacent actions to swap, (index, index + 1). 60 | List swapCandidates = IntStream.range(0, route.size() - 1) 61 | .filter(index -> !arePickupDropffPair(route.get(index), route.get(index+1))) 62 | .boxed() 63 | .collect(toList()); 64 | int index = swapCandidates.get(random.nextInt(swapCandidates.size())); 65 | 66 | 67 | Map oldCapacities = capacities.get(index+1); 68 | // Ask Adam how this works if you're curious. 69 | Map newCapacities = oldCapacities.keySet().stream() 70 | .collect(toMap(k -> k, k -> capacities.get(index).get(k) - oldCapacities.get(k) + capacities.get(index+2).get(k))); 71 | if (newCapacities.values().stream().allMatch(x -> x >= 0)) { 72 | // This is a legal swap! 73 | List newRoute = new ArrayList<>(route); 74 | CommodityAction swappedAction = newRoute.get(index); 75 | newRoute.set(index, newRoute.get(index+1)); 76 | newRoute.set(index+1, swappedAction); 77 | Map> newRoutes = new HashMap<>(routes); 78 | newRoutes.put(selectedTransport, newRoute); 79 | 80 | return Optional.of(new VRPSearchState(problem, newRoutes)); 81 | } 82 | return Optional.empty(); 83 | } 84 | 85 | private boolean hasSwapCandidates(Transport transport) { 86 | List route = routes.get(transport); 87 | return IntStream.range(0, route.size() - 1) 88 | .anyMatch(index -> !arePickupDropffPair(route.get(index), route.get(index+1))); 89 | } 90 | 91 | // Attempts to swap. Probably fails. 92 | public Optional swapBetweenRoutes() { 93 | List candidates = 94 | routes.keySet().stream().filter(t -> routes.get(t).size() > 1).collect(toList()); 95 | Transport firstTransport = candidates.get(random.nextInt(candidates.size())); 96 | List firstRoute = routes.get(firstTransport); 97 | List potentialMovers = firstRoute.stream() 98 | .filter(ca -> ca instanceof CommodityDropoff && ((CommodityDropoff) ca).start instanceof CommodityPickup) 99 | .collect(toList()); 100 | if (potentialMovers.isEmpty()) { 101 | return Optional.empty(); 102 | } 103 | CommodityDropoff mover = 104 | (CommodityDropoff) potentialMovers.get(random.nextInt(potentialMovers.size())); 105 | List secondTransportCandidates = routes.keySet().stream() 106 | .filter(t -> !t.equals(firstTransport) && canFitInFront(t, mover)) 107 | .collect(toList()); 108 | if (secondTransportCandidates.isEmpty()) { 109 | return Optional.empty(); 110 | } 111 | Transport secondTransport = 112 | secondTransportCandidates.get(random.nextInt(secondTransportCandidates.size())); 113 | List newFirstRoute = new ArrayList<>(firstRoute); 114 | newFirstRoute.remove(mover); 115 | newFirstRoute.remove(mover.start); 116 | LinkedList newSecondRoute = new LinkedList<>(routes.get(secondTransport)); 117 | newSecondRoute.push(mover); 118 | newSecondRoute.push((CommodityPickup) mover.start); 119 | Map> newRoutes = new HashMap<>(routes); 120 | newRoutes.put(firstTransport, newFirstRoute); 121 | newRoutes.put(secondTransport, newSecondRoute); 122 | return Optional.of(new VRPSearchState(problem, newRoutes)); 123 | } 124 | 125 | boolean canFitInFront(Transport transport, CommodityDropoff dropoff) { 126 | Map transportCapacity = problem.capacities.get(transport); 127 | Map pickupCapacity = problem.capacities.get(dropoff.start); 128 | for (String key : transportCapacity.keySet()) { 129 | if (transportCapacity.get(key) < pickupCapacity.get(key)) { 130 | return false; 131 | } 132 | } 133 | return true; 134 | } 135 | 136 | boolean arePickupDropffPair(CommodityAction pickup, CommodityAction dropoff) { 137 | return dropoff instanceof CommodityDropoff && ((CommodityDropoff) dropoff).start.equals(pickup); 138 | } 139 | 140 | boolean canSwapWithinRoute(Transport transport) { 141 | return routes.get(transport).size() > 1; 142 | } 143 | 144 | List> capacitiesByIndex(Transport transport) { 145 | if (!capacitiesByTransportByIndex.containsKey(transport)) { 146 | capacitiesByTransportByIndex.put(transport, computeCapacitiesByIndex(transport)); 147 | } 148 | return capacitiesByTransportByIndex.get(transport); 149 | } 150 | 151 | private List> computeCapacitiesByIndex(Transport transport) { 152 | List> result = new ArrayList<>(); 153 | List route = routes.get(transport); 154 | Map current = problem.capacities.get(transport); 155 | result.add(current); 156 | for (int i = 0; i < route.size(); i++) { 157 | Map next = new HashMap<>(current); 158 | for (Map.Entry difference : problem.capacities.get(route.get(i)).entrySet()) { 159 | next.put(difference.getKey(), next.get(difference.getKey()) + difference.getValue()); 160 | } 161 | result.add(next); 162 | } 163 | return result; 164 | } 165 | 166 | @Override 167 | public String toString() { 168 | StringBuilder builder = new StringBuilder(); 169 | for (Map.Entry> entry: routes.entrySet()) { 170 | builder.append(entry.getKey()).append("\n"); 171 | for (CommodityAction action : entry.getValue()) { 172 | builder.append("\t- ").append(action).append("\n"); 173 | } 174 | } 175 | return builder.toString(); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/domain/VehicleRoutingProblem.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.domain; 2 | 3 | import com.google.common.collect.Table; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.stream.Collectors; 10 | 11 | import xyz.thepathfinder.simulatedannealing.InfeasibleProblemException; 12 | import xyz.thepathfinder.simulatedannealing.Problem; 13 | 14 | public class VehicleRoutingProblem implements Problem { 15 | final List transports; 16 | final List commodityDropoffs; 17 | final Table distances; 18 | final Table durations; 19 | final Map> capacities; 20 | 21 | public VehicleRoutingProblem( 22 | List transports, 23 | List commodityDropoffs, 24 | Table distances, 25 | Table durations, 26 | Map> capacities) { 27 | this.transports = transports; 28 | this.commodityDropoffs = commodityDropoffs; 29 | this.distances = distances; 30 | this.durations = durations; 31 | this.capacities = capacities; 32 | } 33 | 34 | @Override 35 | public VRPSearchState initialState() throws InfeasibleProblemException { 36 | Map> routes = transports.stream().collect( 37 | Collectors.toMap(t -> t, t -> new ArrayList<>())); 38 | List inTransitCommodities = new ArrayList<>(); 39 | List waitingCommodities = new ArrayList<>(); 40 | commodityDropoffs.forEach(commodityRequest -> { 41 | if (commodityRequest.start instanceof Transport) { 42 | inTransitCommodities.add(commodityRequest); 43 | } else if (commodityRequest.start instanceof CommodityPickup) { 44 | waitingCommodities.add(commodityRequest); 45 | } 46 | }); 47 | inTransitCommodities.forEach(commodityDropoff -> { 48 | routes.get(commodityDropoff.start).add(commodityDropoff); 49 | }); 50 | for (CommodityDropoff commodityDropoff : waitingCommodities) { 51 | boolean commodityPlaced = false; 52 | for (Transport transport: transports) { 53 | List transportRoute = new ArrayList<>(routes.get(transport)); 54 | transportRoute.add((CommodityPickup) commodityDropoff.start); 55 | transportRoute.add(commodityDropoff); 56 | if (validCapacities(applyCapacities(capacities.get(transport), transportRoute))) { 57 | routes.put(transport, transportRoute); 58 | commodityPlaced = true; 59 | break; 60 | } 61 | } 62 | if (!commodityPlaced) { 63 | throw new InfeasibleProblemException("Unable to create initial state"); 64 | } 65 | } 66 | return new VRPSearchState(this, routes); 67 | } 68 | 69 | @Override 70 | public double energy(VRPSearchState searchState) { 71 | double totalDistance = 0; 72 | for (Map.Entry> route : searchState.routes.entrySet()) { 73 | Transport transport = route.getKey(); 74 | List commodityActions = route.getValue(); 75 | if (!commodityActions.isEmpty()) { 76 | totalDistance += distances.get(transport, commodityActions.get(0)); 77 | } 78 | for (int i = 0; i < commodityActions.size() - 1; i++) { 79 | totalDistance += distances.get(commodityActions.get(i), commodityActions.get(i+1)); 80 | } 81 | } 82 | return totalDistance; 83 | } 84 | 85 | Map applyCapacities( 86 | Map startingCapacities, List actions) { 87 | Map endingCapacities = new HashMap<>(startingCapacities); 88 | actions.forEach(action -> { 89 | capacities.get(action).entrySet().forEach( 90 | e -> endingCapacities.computeIfPresent(e.getKey(), (k, v) -> v + e.getValue())); 91 | }); 92 | return endingCapacities; 93 | } 94 | 95 | private static boolean validCapacities(Map capacities) { 96 | return capacities.values().stream().allMatch(c -> c >= 0); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/service/ProblemDescription.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.service; 2 | 3 | import com.google.common.collect.HashBasedTable; 4 | import com.google.common.collect.Table; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | import xyz.thepathfinder.routing.domain.CommodityDropoff; 13 | import xyz.thepathfinder.routing.domain.CommodityPickup; 14 | import xyz.thepathfinder.routing.domain.CommodityStart; 15 | import xyz.thepathfinder.routing.domain.RouteAction; 16 | import xyz.thepathfinder.routing.domain.Transport; 17 | import xyz.thepathfinder.routing.domain.VehicleRoutingProblem; 18 | 19 | import static java.util.stream.Collectors.toMap; 20 | 21 | public class ProblemDescription { 22 | private List transports; 23 | private Map commodities; 24 | private Integer[][] durations; 25 | private Integer[][] distances; 26 | private Map> capacities; 27 | private Map> parameters; 28 | private String objective; 29 | 30 | public void setTransports(List transports) { 31 | this.transports = transports; 32 | } 33 | 34 | public void setCommodities(Map commodities) { 35 | this.commodities = commodities; 36 | } 37 | 38 | public void setDurations(Integer[][] durations) { 39 | this.durations = durations; 40 | } 41 | 42 | public void setDistances(Integer[][] distances) { 43 | this.distances = distances; 44 | } 45 | 46 | public void setCapacities(Map> capacities) { 47 | this.capacities = capacities; 48 | } 49 | 50 | public void setParameters(Map> parameters) { 51 | this.parameters = parameters; 52 | } 53 | 54 | public void setObjective(String objective) { 55 | this.objective = objective; 56 | } 57 | 58 | public List getTransports() { 59 | return transports; 60 | } 61 | 62 | public Map getCommodities() { 63 | return commodities; 64 | } 65 | 66 | public Integer[][] getDurations() { 67 | return durations; 68 | } 69 | 70 | public Integer[][] getDistances() { 71 | return distances; 72 | } 73 | 74 | public Map> getCapacities() { 75 | return capacities; 76 | } 77 | 78 | public Map> getParameters() { 79 | return parameters; 80 | } 81 | 82 | public String getObjective() { 83 | return objective; 84 | } 85 | 86 | @Override 87 | public String toString() { 88 | return new StringBuilder() 89 | .append("Transports: ").append(transports).append("\n") 90 | .append("Commodities: " ).append(commodities).append("\n") 91 | .append("Distances: ").append(Arrays.deepToString(distances)).append("\n") 92 | .append("Durations: ").append(Arrays.deepToString(durations)).append("\n") 93 | .append("Capacities: ").append(capacities).append("\n") 94 | .append("Parameters: ").append(parameters).append("\n") 95 | .append("Objective: ").append(objective) 96 | .toString(); 97 | } 98 | 99 | public VehicleRoutingProblem createProblem() { 100 | Map transportMap = transports.stream().collect( 101 | toMap(n -> n, n -> new Transport(String.valueOf(n)))); 102 | List commodityDropoffList = new ArrayList<>(); 103 | Map routeActionMap = new HashMap<>(); 104 | routeActionMap.putAll(transportMap); 105 | for (Map.Entry commodityEntry : commodities.entrySet()) { 106 | CommodityStart start; 107 | if (transportMap.containsKey(commodityEntry.getKey())) { 108 | start = transportMap.get(commodityEntry.getKey()); 109 | } else { 110 | int pickupId = commodityEntry.getValue(); 111 | start = new CommodityPickup(String.valueOf(pickupId)); 112 | routeActionMap.put(pickupId, (CommodityPickup) start); 113 | } 114 | int dropoffId = commodityEntry.getKey(); 115 | CommodityDropoff dropoff = new CommodityDropoff(String.valueOf(dropoffId), start); 116 | commodityDropoffList.add(dropoff); 117 | routeActionMap.put(dropoffId, dropoff); 118 | } 119 | Table distanceTable = HashBasedTable.create(); 120 | Table durationTable = HashBasedTable.create(); 121 | for (int r = 0; r < distances.length; r++) { 122 | for (int c = 0; c < distances[r].length; c++) { 123 | if (routeActionMap.containsKey(r+1) && routeActionMap.containsKey(c+1)) { 124 | RouteAction ra1 = routeActionMap.get(r+1); 125 | RouteAction ra2 = routeActionMap.get(c+1); 126 | distanceTable.put(ra1, ra2, distances[r][c]); 127 | distanceTable.put(ra2, ra1, distances[r][c]); 128 | durationTable.put(ra1, ra2, durations[r][c]); 129 | durationTable.put(ra2, ra1, durations[r][c]); 130 | } 131 | } 132 | } 133 | 134 | Map> allCapacities = 135 | routeActionMap.values().stream().collect(toMap(a -> a, a -> new HashMap<>())); 136 | for (Map.Entry> e1 : capacities.entrySet()) { 137 | for (Map.Entry e2 : e1.getValue().entrySet()) { 138 | RouteAction routeAction = routeActionMap.get(e2.getKey()); 139 | // Dan sends negative for dropoff, positive for pickup. 140 | int value = routeAction instanceof Transport ? e2.getValue() : -1 * e2.getValue(); 141 | allCapacities.get(routeAction).put(e1.getKey(), value); 142 | } 143 | } 144 | 145 | return new VehicleRoutingProblem( 146 | new ArrayList(transportMap.values()), 147 | commodityDropoffList, 148 | distanceTable, 149 | durationTable, 150 | allCapacities); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/service/ProblemSolution.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.service; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import xyz.thepathfinder.routing.domain.CommodityAction; 8 | import xyz.thepathfinder.routing.domain.Transport; 9 | 10 | public class ProblemSolution { 11 | private List> routes; 12 | 13 | public ProblemSolution() { } 14 | 15 | public static ProblemSolution create(Map> routes) { 16 | List> integerRoutes = new ArrayList<>(); 17 | for (Map.Entry> routeEntry : routes.entrySet()) { 18 | List singleRoute = new ArrayList<>(); 19 | singleRoute.add(Integer.parseInt(routeEntry.getKey().getName())); 20 | for (CommodityAction action : routeEntry.getValue()) { 21 | singleRoute.add(Integer.parseInt(action.getName())); 22 | } 23 | integerRoutes.add(singleRoute); 24 | } 25 | return new ProblemSolution(integerRoutes); 26 | } 27 | 28 | public ProblemSolution(List> routes) { 29 | this.routes = routes; 30 | } 31 | 32 | public void setRoutes(List> routes) { 33 | this.routes = routes; 34 | } 35 | 36 | public List> getRoutes() { 37 | return routes; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/java/xyz/thepathfinder/routing/service/RoutingService.java: -------------------------------------------------------------------------------- 1 | package xyz.thepathfinder.routing.service; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import javax.ws.rs.Consumes; 7 | import javax.ws.rs.POST; 8 | import javax.ws.rs.Path; 9 | import javax.ws.rs.Produces; 10 | import javax.ws.rs.core.MediaType; 11 | 12 | import xyz.thepathfinder.routing.domain.VRPSearchState; 13 | import xyz.thepathfinder.simulatedannealing.InfeasibleProblemException; 14 | import xyz.thepathfinder.simulatedannealing.LinearDecayScheduler; 15 | import xyz.thepathfinder.simulatedannealing.Problem; 16 | import xyz.thepathfinder.simulatedannealing.Scheduler; 17 | import xyz.thepathfinder.simulatedannealing.Solver; 18 | 19 | @Path("/") 20 | public class RoutingService { 21 | private static final double INITIAL_TEMPERATURE = 50000; 22 | private static final int NUMBER_OF_STEPS = 1000000; 23 | 24 | Logger logger = LoggerFactory.getLogger(RoutingService.class); 25 | 26 | @POST 27 | @Consumes(MediaType.APPLICATION_JSON) 28 | @Produces(MediaType.APPLICATION_JSON) 29 | public ProblemSolution solveProblem(ProblemDescription problemDescription) 30 | throws InfeasibleProblemException { 31 | logger.info("Received request to route"); 32 | Scheduler scheduler = new LinearDecayScheduler(INITIAL_TEMPERATURE, NUMBER_OF_STEPS); 33 | Problem problem = problemDescription.createProblem(); 34 | Solver solver = new Solver(problem, scheduler); 35 | VRPSearchState solution = solver.solve(); 36 | return ProblemSolution.create(solution.getRoutes()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /simulatedannealing/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Pathfinder Routing Server 4 | 5 | routing 6 | com.sun.jersey.spi.container.servlet.ServletContainer 7 | 8 | com.sun.jersey.config.property.packages 9 | xyz.thepathfinder.routing.service 10 | 11 | 12 | com.sun.jersey.api.json.POJOMappingFeature 13 | true 14 | 15 | 1 16 | 17 | 18 | routing 19 | /* 20 | 21 | 22 | -------------------------------------------------------------------------------- /simulatedannealing/stress_test/tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import requests 5 | import time 6 | import random 7 | import sys 8 | import math 9 | 10 | def distance(a, b): 11 | x1, y1 = a 12 | x2, y2 = b 13 | return int(24494*math.sqrt(math.pow(x1-x2,2) + math.pow(y1-y2,2))) 14 | 15 | M = 30 16 | MAX_T = 10 17 | MAX_C = 8 18 | coordinates = [(random.random(), random.random()) for i in range(M)] 19 | distance_matrix = [[distance(coordinates[a],coordinates[b]) for a in range(M)] for b in range(M)] 20 | 21 | def data(t, c): 22 | if t + 2*c > len(distance_matrix): 23 | raise Exception 24 | transports = range(1, t + 1) 25 | commodities = { x: x + c for x in range(t + 1, t + c + 1) } 26 | return { 27 | 'transports': transports, 28 | 'commodities': commodities, 29 | 'durations': distance_matrix, 30 | 'distances': distance_matrix, 31 | 'capacities': { 32 | 'capacity': dict({t: 3 for t in transports}, **dict({commodities[d]: 1 for d in commodities}, **{d: -1 for d in commodities})) 33 | }, 34 | 'parameters': { 35 | }, 36 | 'objective': """ 37 | @setObjective(model, Min, sum{distance[i],i=TA}) 38 | """ 39 | } 40 | 41 | def time_request(url, data): 42 | start = time.time() 43 | r = requests.post(url, json=data) 44 | print "{0:.2f}".format(time.time() - start), 45 | print "(" + str(route_length(json.loads(r.text)['routes'])) +") |", 46 | sys.stdout.flush() 47 | 48 | def test(url, t, c): 49 | time_request(url, data(t, c)) 50 | #time_request('http://routing3.thepathfinder.xyz:8080/pathfinder-routing', data(t, c)) 51 | 52 | def testlocal(t, c): 53 | time_request('http://localhost:8080/routing', data(t, c)) 54 | 55 | def testold(t, c): 56 | time_request('http://routing.thepathfinder.xyz', data(t, c)) 57 | 58 | def route_length(routes): 59 | return sum(distance_matrix[a-1][b-1] for [a, b] in sum([zip(r[:len(r)-1],r[1:]) for r in routes], [])) 60 | 61 | def pretty_test(name, url): 62 | print name 63 | print 64 | print '||', 65 | for i in range(1,MAX_C): 66 | print 'C='+str(i)+' |', 67 | print 68 | for i in range(0,MAX_C): 69 | print '|---', 70 | print '|' 71 | for i in range(1,MAX_T): 72 | print '|T='+str(i)+'|', 73 | [test(url,i,c) for c in range(1,MAX_C)] 74 | print 75 | 76 | if __name__ == '__main__': 77 | pretty_test('SA - Linear (T=100, N=1000000)', 'http://routing3.thepathfinder.xyz:8080/pathfinder-routing-linear-100') 78 | pretty_test('SA - Linear (T=1000, N=1000000)', 'http://routing3.thepathfinder.xyz:8080/pathfinder-routing-linear-1000') 79 | pretty_test('SA - Linear (T=10000, N=1000000)', 'http://routing3.thepathfinder.xyz:8080/pathfinder-routing-linear-10000') 80 | pretty_test('SA - Exponential (T=100, N=1000000)', 'http://routing3.thepathfinder.xyz:8080/pathfinder-routing-exp-100') 81 | pretty_test('SA - Exponential (T=1000, N=1000000)', 'http://routing3.thepathfinder.xyz:8080/pathfinder-routing-exp-1000') 82 | pretty_test('SA - Exponential (T=10000, N=1000000)', 'http://routing3.thepathfinder.xyz:8080/pathfinder-routing-exp-10000') 83 | pretty_test('Optaplanner', 'http://routing2.thepathfinder.xyz') 84 | -------------------------------------------------------------------------------- /simulatedannealing/stress_test/top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CSSE497/pathfinder-routing/c234fdfe8eebc2799b39f7071cc0091884f71a26/simulatedannealing/stress_test/top.png --------------------------------------------------------------------------------