public void Run() { var api = new ApiHelper <Tsp.SolveRequest, Tsp.SolutionResponse>("tsp-mcvfz472gty6", configFile); // so here we're going to build the model // create a solve request Tsp.SolveRequest sr = new Tsp.SolveRequest(); sr.Model = new Tsp.Tsp(); // initialise the model container // add points to the tsp model foreach (var d in data) { sr.Model.Points.Add(new Tsp.Geocode { Id = d.id, X = d.X, Y = d.Y }); } // configure the distance metric (although road network is the default) sr.Model.Distancetype = Tsp.Tsp.eDistanceType.RoadNetwork; string requestId = api.Post(sr); // send the model to the api Solution = api.Get(requestId); // get the response (which it typed, so that's cool) // lets pull out the total distance lineString ls = new lineString(); double totalDistance = 0.0; foreach (var e in Solution.Edges) { totalDistance += e.Distance; foreach (var g in e.Geometries) { ls.Add(new double[2] { g.X, g.Y }); } } System.Console.WriteLine(string.Format("Total distance: {0:0.00} km\t Stops: " + Solution.Tours.Count, totalDistance)); // just for fun - you wouldn't ever plot things this way - but it is nice to see the line segments new consolePlot(new List <lineString> { ls }); return; }
public void Run() { var api = new ApiHelper <Cvrptw.SolveRequest, Cvrptw.SolutionResponse>("cvrptw-acyas3nzweqb", configFile); // so here we're going to build the model // create a solve request Cvrptw.SolveRequest sr = new Cvrptw.SolveRequest(); sr.Model = new Cvrptw.Cvrptw(); // initialise the model container // add the depot (first point) in the model for (int i = 0; i < data.Count; i++) { if (i == 0) { sr.Model.Depot = new Cvrptw.Geocode { Id = data[i].id, X = (float)data[i].X, Y = (float)data[i].Y, Quantity = (float)0.0 }; // this adds the depot to the model } else { // add the points as demand points. Assume that each point has a demand quantity of 20 // lets randomly split the windows into "morning" and "afternoon" windows // note that the windows are measured in minutes in this schema. sr.Model.Points.Add(new Cvrptw.Geocode { Id = data[i].id, X = (float)data[i].X, Y = (float)data[i].Y, windowStart = i % 2 == 0 ? (float)(8 * 60) : (float)(12 * 60), windowEnd = i % 2 == 0 ? (float)(12 * 60) : (float)(16 * 60), Quantity = (float)20 }); } } // configure the distance metric (although road network is the default) sr.Model.Distancetype = Cvrptw.Cvrptw.eDistanceType.RoadNetwork; sr.Model.VehicleCapacity = 100; // set a vehicle capacity of 100 sr.Model.NumberOfVehicles = 3; // allow the use of at-most, three vehicles string requestId = api.Post(sr); // send the model to the api Solution = api.Get(requestId); // get the response (which it typed, so that's cool) // lets pull out the total distance lineString ls = new lineString(); double totalDistance = 0.0; int stopCount = 0; foreach (var r in Solution.Routes) { stopCount += r.Sequences.Count; foreach (var e in r.Edges) { totalDistance += e.Distance; } } Console.WriteLine(string.Format("Total Cost: {0:0.00} \t ", Solution.Objective)); Console.WriteLine(string.Format("Total distance: {0:0.00} km\t Stops: " + stopCount, totalDistance)); foreach (var r in Solution.Routes) { if (r.Sequences.Count > 0) { Console.WriteLine("Route: "); int stopc = 1; double vCap = 0.0; for (int i = 0; i < r.Sequences.Count; i++) { vCap += r.visitCapacities[i]; Console.WriteLine(" stop " + stopc + ": " + (int)(vCap) + ", " + r.Sequences[i] + ", " + r.arrivalTimes[i]); stopc++; } } } // the cumulative quantity assigned to each route is <= 100. return; }
public static void printSolution(Ns3.SolutionResponse resp, Ns3.SolveRequest sr) { // we're just going to show the first 5 items from each table that one can construct here. // we also give an illustration of how to construct the geometries in this context. //assignment table. int[] maxchar = new int[] { "Lane Rate".Length, "Cost Model".Length, "Source".Length, "Destination".Length, "Product".Length, "Amount".Length, "Cost".Length, "Distance".Length, "Duration".Length }; foreach (var a in resp.Assignments) { maxchar[0] = Math.Max(maxchar[0], a.laneRateId.Length); maxchar[1] = Math.Max(maxchar[1], a.costModelId.Length); maxchar[2] = Math.Max(maxchar[2], a.Source.Length); maxchar[3] = Math.Max(maxchar[3], a.Destination.Length); maxchar[4] = Math.Max(maxchar[4], a.productId.Length); //a.Amount //a.Cost //a.Distance //a.Duration } Console.WriteLine("Assignments:"); string formatLine = "|{0,-" + maxchar[0] + "}|{1,-" + maxchar[1] + "}|{2,-" + maxchar[2] + "}|{3,-" + maxchar[3] + "}|{4,-" + maxchar[4] + "}|{5,10}|{6,10}|{7,10}|{8,10}|"; Console.WriteLine(String.Format(formatLine, "Lane Rate", "Cost Model", "Source", "Destination", "Product", "Amount", "Cost", "Distance", "Duration")); int maxprint = 0; foreach (var a in resp.Assignments) { Console.WriteLine(String.Format(formatLine, a.laneRateId, a.costModelId, a.Source, a.Destination, a.productId, string.Format("{0:0.00}", a.Amount), string.Format("{0:0.00}", a.Cost), string.Format("{0:0.00}", a.Distance), string.Format("{0:0.00}", a.Duration))); maxprint++; if (maxprint > 10) { Console.WriteLine("table truncated..."); maxprint = 0; break; } } Console.WriteLine(""); Console.WriteLine("Node Flow:"); maxchar[0] = "NodeId".Length; foreach (var nf in resp.nodeFlows) { maxchar[0] = Math.Max(maxchar[0], nf.nodeId.Length); } formatLine = "|{0,-" + maxchar[0] + "}|{1,10}|{2,10}|{3,10}|{4,10}|{5," + "ProductFixedCost".Length + "}|{6," + "ProductFlowCost".Length + "}|{7,10}|{8,10}|{9,10}|{10,10}|{11,10}|{12,10}|"; Console.WriteLine(String.Format(formatLine, "NodeId", "InFlow", "OutFlow", "FixedCost", "FlowCost", "ProductFixedCost", "ProductFlowCost", "P-Amount", "P-Cost", "P-Penalty", "C-Amount", "C-Cost", "C-Penalty")); foreach (var nf in resp.nodeFlows) { Console.WriteLine(String.Format(formatLine, nf.nodeId, string.Format("{0:0.00}", nf.inFlow), string.Format("{0:0.00}", nf.outFlow), string.Format("{0:0.00}", nf.fixedCost), string.Format("{0:0.00}", nf.flowCost), string.Format("{0:0.00}", nf.productFixedCost), string.Format("{0:0.00}", nf.productFlowCost), string.Format("{0:0.00}", nf.productionAmount), string.Format("{0:0.00}", nf.productionCost), string.Format("{0:0.00}", nf.productionPenalty), string.Format("{0:0.00}", nf.consumptionAmount), string.Format("{0:0.00}", nf.consumptionCost), string.Format("{0:0.00}", nf.consumptionPenalty))); maxprint++; if (maxprint > 10) { Console.WriteLine("table truncated..."); maxprint = 0; break; } } Console.WriteLine(""); Console.WriteLine("Node Product Flow:"); maxchar[0] = "NodeId".Length; maxchar[1] = "ProductId".Length; foreach (var nf in resp.nodeFlows) { maxchar[0] = Math.Max(maxchar[0], nf.nodeId.Length); } formatLine = "|{0,-" + maxchar[0] + "}|{1,-" + maxchar[1] + "}|{2,10}|{3,10}|{4,10}|{5,10}|{6,10}|{7,10}|{8,10}|{9,10}|{10,10}|{11,10}|"; Console.WriteLine(String.Format(formatLine, "NodeId", "ProductId", "InFlow", "OutFlow", "FixedCost", "FlowCost", "P-Amount", "P-Cost", "P-Penalty", "C-Amount", "C-Cost", "C-Penalty")); foreach (var nf in resp.nodeProductFlows) { Console.WriteLine(String.Format(formatLine, nf.nodeId, nf.productId, string.Format("{0:0.00}", nf.inFlow), string.Format("{0:0.00}", nf.outFlow), string.Format("{0:0.00}", nf.fixedCost), string.Format("{0:0.00}", nf.flowCost), string.Format("{0:0.00}", nf.productionAmount), string.Format("{0:0.00}", nf.productionCost), string.Format("{0:0.00}", nf.productionPenalty), string.Format("{0:0.00}", nf.consumptionAmount), string.Format("{0:0.00}", nf.consumptionCost), string.Format("{0:0.00}", nf.consumptionPenalty))); maxprint++; if (maxprint > 10) { Console.WriteLine("table truncated..."); maxprint = 0; break; } } // lets unpack the geometries for each of the "routes" List <lineString> routeData = new List <lineString>(); foreach (var r in resp.Routes) { lineString ls = new lineString(); foreach (var i in r.geometrySequences) { for (int j = 0; j < resp.geometrySequences[i].X.Length; j++) { ls.Add(new double[2] { resp.geometrySequences[i].X[j], resp.geometrySequences[i].Y[j] }); } } routeData.Add(ls); } var cplot = new consolePlot(routeData); }
public void Run() { var api = new ApiHelper <Tsptw.SolveRequest, Tsptw.SolutionResponse>("tsptw-kcxbievqo879", configFile); // so here we're going to build the model // create a solve request Tsptw.SolveRequest sr = new Tsptw.SolveRequest(); sr.Model = new Tsptw.Tsp(); // initialise the model container Random rand = new Random(); // add points to the tsp model foreach (var d in data) { // lets randomly create a window here. double rupper = 2500; double ws = rand.NextDouble() * rupper; double we = ws + rupper; //we don't accept backwards windows, so we'll just set these to some positive width upper amount. sr.Model.Points.Add(new Tsptw.Geocode { Id = d.id, X = d.X, Y = d.Y, windowStart = (float)ws, windowEnd = (float)we, }); } // configure the distance metric (although road network is the default) sr.Model.Distancetype = Tsptw.Tsp.eDistanceType.RoadNetwork; string requestId = api.Post(sr); // send the model to the api Solution = api.Get(requestId); // get the response (which it typed, so that's cool) // lets pull out the total distance lineString ls = new lineString(); double totalDistance = 0.0; foreach (var e in Solution.Edges) { totalDistance += e.Distance; foreach (var g in e.Geometries) { ls.Add(new double[2] { g.X, g.Y }); } } Console.WriteLine(string.Format("Total distance: {0:0.00} km\t Stops: " + Solution.Tours.Count, totalDistance)); int maxchar = 0; foreach (var d in data) { maxchar = Math.Max(d.id.Length, maxchar); // so that the table displays nicely in the console :-) } string formatLine = "|{0,-" + maxchar + "}|{1,11}|"; Console.WriteLine(String.Format(formatLine, "Location", "ArrivalTime")); for (int i = 0; i < Solution.arrivalTimes.Length; i++) { Console.WriteLine(String.Format(formatLine, Solution.Tours[i], Solution.arrivalTimes[i])); } // just for fun - you wouldn't ever plot things this way - but it is nice to "see" the line segments Console.WriteLine("Approximate Tour Map:"); new consolePlot(new List <lineString> { ls }); return; }
public void Run() { var api = new ApiHelper <Ivr7.SolveRequest, Ivr7.SolutionResponse>("ivr7-kt461v8eoaif", configFile); // so here we're going to build the model // create a solve request Ivr7.SolveRequest sr = new Ivr7.SolveRequest(); sr.Model = new Ivr7.Model(); // initialise the model container // the first decision we have to make is which dimensional quantities to model in this example. // we're going to model the distance, time, and capacity of the vehicle. ivr7helper.makeDistanceTimeCapDims(sr.Model); // adds distance, time & capacity // lets pretend the first point is where vehicles are going to begin and end each day. // unlike the tsp/cvrp/pdp models, the ivr7 requires that you specify the unique locations // that are going to be used in the model as a separate entity. The reason for this is that you // can then specify the locations once, and reference those locations by id for other entities (such and vehicles/jobs/tasks) ivr7helper.makeLocations(sr.Model, data); // adds all the locations to the model // so we've constructed some jobs with pickups and dropoffs, loading and offload times, as well as the // contribution to the capacity dimension. In this example, we're pickup up all orders at the guiness storehouse // and delivering at the list of customers. 'make_job_time_cap' is just a simple function to create this // particular style of request, but you can make your own. ivr7helper.makeJobTimeCap(sr.Model, data, ivr7helper.Rep(0, data.Count - 1), ivr7helper.Seq(1, data.Count)); // we're going to do the vehicle-configuration now. // we need to specify the cost classes available, the vehicle classes available, and then the individual vehicles. // we're going to create one of each to keep things simple. sr.Model.vehicleCostClasses.Add(ivr7helper.makeVccSimple("vcc1", 1000, 0.01f, 0.01f, 0.01f, 1, 3)); // lets make the vehicle class. A vehicle class describes how the vehicle MOVES through the network. // so in other words, we can use the standard network travel speeds, or we could make the vehicle // move slower/faster relative to the road network. We could also attach transit rules here which are // great for modelling lunch breaks, refueling stops etc. (i.e. conditional triggers on the cumul values // of the dimension). Covered in an advanced section. sr.Model.vehicleClasses.Add(ivr7helper.makeVcSimple("vc1", 1, 1, 1, 1)); // now we can just specify the vehicles. // lets provide 2 x 2 ton vehicles. Although this is probably more than we need. // the reason for this is that we're modelling a full-blown pickup+dropoff model, so if there's // time to reload, a vehicle can return to the depot and grab more goodies! for (int i = 0; i < 2; i++) { sr.Model.Vehicles.Add(ivr7helper.makeVehicleCap("vehicle_" + i, // unique id for the vehicle. "vc1", // the vehicle class "vcc1", // the vehicle cost class 2000, // the capacity of the vehicle data[0].id, // start location for the vehicle data[0].id, // end location for the vehicle 7 * 60, // start time: 7 AM 18 * 60 // end time: 6 PM )); } sr.solveType = Ivr7.SolveRequest.SolveType.Optimise; // Optimise the solve request. // now it's just sending the model to the api string requestId = api.Post(sr); // send the model to the api Solution = api.Get(requestId); // get the response (which it typed, so that's cool) // lets pull out the total distance lineString ls = new lineString(); double totalDistance = 0.0; int stopCount = 0; foreach (var r in Solution.Routes) { foreach (var e in r.interStops) { foreach (var a in e.Attributes) { if (a.dimId == "distance") { totalDistance += (a.endValue - a.startValue); // the difference between the start and end value } } foreach (var g in e.routeSegments) { ls.Add(new double[] { g.Longitude, g.Latitude }); // these are the road-network edges if you want to visualise the route in //leaflet or on a map. } } } Console.WriteLine(string.Format("Total Cost: {0:0.00} \t ", Solution.Objective)); Console.WriteLine(string.Format("Total distance: {0:0.00} km\t Stops: " + stopCount, totalDistance)); ivr7helper.printSolution(Solution); // the maximum quantity assigned to each vehicle is <= 2000 (the capacity dimension). // the majority of the cost is coming in the distance dimension (because of the way we've configured the vehicle cost class) // for visualisations see the R/python notebook for plots on the same example. return; }
public void Run() { var api = new ApiHelper <Ivr7.SolveRequest, Ivr7.SolutionResponse>("ivr7-kt461v8eoaif", configFile); // so here we're going to build the model // create a solve request Ivr7.SolveRequest sr = new Ivr7.SolveRequest(); sr.Model = new Ivr7.Model(); // initialise the model container // we're going to reuse the helpers described in the ivr7basic example. Please see that for a reference. ivr7helper.makeDistanceTimeCapDims(sr.Model); // adds distance, time & capacity ivr7helper.makeLocations(sr.Model, data); // adds all the locations to the model // we're going to add time windows to the locations. 08:00 - 14:00 foreach (var l in sr.Model.Locations) { var a = new Ivr7.Location.Attribute() { dimensionId = "time", arrivalWindows = { new Ivr7.Window { Start = 8 * 60, End = 14 * 60 } } }; l.Attributes.Add(a); } ivr7helper.makeJobTimeCap(sr.Model, data, ivr7helper.Rep(0, data.Count - 1), ivr7helper.Seq(1, data.Count)); // Two vehicle cost classes, one which is cheaper on time, one which is cheaper on distance, one // which is more expensive if used (1000 vs 1200). sr.Model.vehicleCostClasses.Add(ivr7helper.makeVccSimple("vcc1", 1000, 0.01f, 0.01f, 0.01f, 1, 3)); sr.Model.vehicleCostClasses.Add(ivr7helper.makeVccSimple("vcc2", 1200, 0.1f, 0.1f, 0.1f, 0.6f, 2.5f)); sr.Model.vehicleClasses.Add(ivr7helper.makeVcSimple("vc1", 1, 1, 1, 1)); // now we can just specify the vehicles. // lets provide 2 x 2 ton vehicles and 2 x 3 ton vehicles. Although this is probably more than we need. // the reason for this is that we're modelling a full-blown pickup+dropoff model, so if there's // time to reload, a vehicle can return to the depot and grab more goodies! for (int i = 0; i < 4; i++) { string vcc = "vcc1"; float cap = 2000; if (i > 1) { vcc = "vcc2"; cap = 3000; } sr.Model.Vehicles.Add(ivr7helper.makeVehicleCap("vehicle_" + i, // unique id for the vehicle. "vc1", // the vehicle class vcc, // the vehicle cost class cap, // the capacity of the vehicle data[0].id, // start location for the vehicle data[0].id, // end location for the vehicle 7 * 60, // start time: 7 AM 18 * 60 // end time: 6 PM )); } // Lunch breaks. // so this is a touch more complex, we want to link our transit-rule to the time // dimension, and when a certain amount has accumulated on the dimension, we trigger the rule. sr.Model.transitRules.Add(ivr7helper.makeLunchBreakRule("lunch_break_rule", "lunchy_munchy_", 12 * 60, 60)); // now link the transit rule to the vehicle classes sr.Model.vehicleClasses[0].transitRuleIds.Add("lunch_break_rule"); sr.solveType = Ivr7.SolveRequest.SolveType.Optimise; // Optimise the solve request. // now it's just sending the model to the api string requestId = api.Post(sr); // send the model to the api Solution = api.Get(requestId); // get the response (which it typed, so that's cool) // lets pull out the total distance lineString ls = new lineString(); double totalDistance = 0.0; int stopCount = 0; foreach (var r in Solution.Routes) { foreach (var e in r.interStops) { foreach (var a in e.Attributes) { if (a.dimId == "distance") { totalDistance += (a.endValue - a.startValue); // the difference between the start and end value } } foreach (var g in e.routeSegments) { ls.Add(new double[] { g.Longitude, g.Latitude }); // these are the road-network edges if you want to visualise the route in //leaflet or on a map. } } } Console.WriteLine(string.Format("Total Cost: {0:0.00} \t ", Solution.Objective)); Console.WriteLine(string.Format("Total distance: {0:0.00} km\t Stops: " + stopCount, totalDistance)); ivr7helper.printSolution(Solution); // the maximum quantity assigned to each vehicle is <= 2000 (the capacity dimension). // the majority of the cost is coming in the distance dimension (because of the way we've configured the vehicle cost class) // for visualisations see the R/python notebook for plots on the same example. return; }