public void Run() { var api = new ApiHelper <Ns3.SolveRequest, Ns3.SolutionResponse>("ns3-tbfvuwtge2iq", configFile); // so here we're going to build the model var m = new Ns3.Model(); m.Dimensions = ns3helper.make_distance_time_user_dimensions("weight"); var productionNodes = data.Where(q => q.quanity == -1).ToList(); var warehouseNodes = data.Where(q => q.quanity == -2).ToList(); var demandNodes = data.Where(q => q.quanity > 0).ToList(); var p_nodes = ns3helper.make_nodes(productionNodes); var w_nodes = ns3helper.make_nodes(warehouseNodes); var d_nodes = ns3helper.make_nodes(demandNodes); // lets assume we can go factory-direct or through a warehouse! var sources = data.Where(q => q.quanity < 0).Select(t => t.id).ToList(); // lets continue to make some alterations. // we know that demand nodes require us to fulfill the demand at the node. // lets assume we have no production constraints // we have a reasonably even demand profile - something tells us this data-set is not real! :-) // demandNodes$demand %>% hist // in order to specify which demands we should satisfy, lets place a flow requirement at each node. for (int i = 0; i < d_nodes.Count; i++) { // each demand node must have the quantity demand[i] delivered, so the range here // is actually [demand[i], demand[i]]. // Not meeting this range incurs a large penalty cost. d_nodes[i].Consumptions.Add( new Ns3.Node.ProductFlow { productId = "Beer", dimensionRanges = { ns3helper.make_dimension_range("weight", demandNodes[i].quanity, demandNodes[i].quanity) } } ); d_nodes[i].allowableSources.AddRange(sources); // all sources are allowable } for (int i = 0; i < p_nodes.Count; i++) { // the production node has no limit on the amount that can be produced. // so we can simply set the upper bound to the sum of all demand, i.e. [0, sum(demands)] // this way we know that the facility can produce enough to satisfy all the demand p_nodes[i].Productions.Add( new Ns3.Node.ProductFlow { productId = "Beer", dimensionRanges = { ns3helper.make_dimension_range("weight", 0, demandNodes.Sum(t => t.quanity)) } } ); p_nodes[i].Productions[0].dimensionRanges[0].flowPenalty = 0; } m.Nodes.AddRange(p_nodes); m.Nodes.AddRange(w_nodes); m.Nodes.AddRange(d_nodes); // so Guiness Storehouse -> Limerick // and Guinnes Storehouse -> Galway // each costed at 0.1 monetary units per km. m.laneRates.Add(ns3helper.make_lane_rate_distance(sources[0], sources[1], 0.1f)); m.laneRates.Add(ns3helper.make_lane_rate_distance(sources[0], sources[2], 0.1f)); m.productGroups.Add(ns3helper.make_single_product_group("Beer")); for (int i = 0; i < sources.Count; i++) { m.costModels.Add(ns3helper.make_cost_model_distance(sources[i], 0.2f)); } Ns3.SolveRequest sr = new Ns3.SolveRequest { Model = m, geometryOutput = Ns3.SolveRequest.GeometryOutput.Aggregate, solveType = Ns3.SolveRequest.SolveType.Optimise }; // 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) ns3helper.printSolution(Solution, sr); // for nice visualisations see the R/python notebook for the same example. 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); }