Beispiel #1
0
        public Report GenerateReport(Network net)
        {
            Optimization optimal = net.OptimizationResult;

            Report report = new Report();
            report.ReportedNetwork = net;
            report.UnoptimizedReport = new UnoptimizedSection();

            if(optimal != null)
            {
                var optimizedReport = new OptimizedSection()
                {
                    TotalCost = optimal.TotalCost,
                    LinkCosts = new Dictionary<Link, LinkCost>(),
                    RawOptimization = optimal
                };

                foreach(var olink in optimal.Links)
                {
                    var link = olink.Link;
                    LinkCost lcost = new LinkCost();

                    lcost.CarFlowCost = olink.Flow * link.Distance * net.CarCostPerMile;

                    lcost.LocomotiveCost = olink.CurrentTrains * link.Distance
                        * (net.FuelCostPerMile + net.NonFuelCostPerMile);

                    optimizedReport.LinkCosts.Add(link, lcost);
                }

                report.OptimizedReport = optimizedReport;
            }

            return report;
        }
        public Dictionary<Node, Dictionary<Link, int>> TranslateToNodes(
			Dictionary<string, Dictionary<string, int>> sol, Network net)
        {
            var r = new Dictionary<Node, Dictionary<Link, int>>();
            foreach(var node in sol)
            {
                var nodeActual = net.Nodes.Where(n => n.StationCode == node.Key).First();
                r[nodeActual] = new Dictionary<Link,int>();
                foreach(var link in node.Value)
                {
                    string[] nodeNames = link.Key.Split('>');
                    var linkActual = net.Links.Where(
                        n => n.From.StationCode == nodeNames[0]
                        && n.To.StationCode == nodeNames[1]).First();

                    r[nodeActual][linkActual] = link.Value;
                }
            }
            return r;
        }
Beispiel #3
0
        public Network XmlFileToNetwork(XDocument inFile)
        {
            var nodes = new List<Node>();
            var links = new List<Link>();
            var orders = new List<Order>();
            int maxCars = 0;
            double nonFuelCost = 0, fuelCost = 0, carCost = 0;
            var nodeCurAdjMap = new Dictionary<Node, double>();
            int i =0;
            foreach (XElement element in inFile.Root.Elements())
            {
                i++;
                switch (element.Name.ToString())
                {
                    case "Network":
                    foreach (XAttribute a in element.Attributes())
                    {
                        switch (a.Name.ToString())
                        {
                            case "maxCars":
                                maxCars = int.Parse(a.Value);
                                break;
                            case "nonFuelCost":
                                nonFuelCost = Double.Parse(a.Value);
                                break;
                            case "fuelCost":
                                fuelCost = Double.Parse(a.Value);
                                break;
                            case "carCost":
                                carCost = Double.Parse(a.Value);
                                break;
                        }
                    }
                    foreach (XElement el in element.Elements())
                    {
                        switch(el.Name.ToString())
                        {
                            case "Nodes":
                            foreach (XElement e in el.Elements())
                            {
                                string stationId = "", name = "";
                                int carCap = 0; //outCapacity = 0;
                                double latitude = 0, longitude = 0;
                                foreach (XAttribute att in e.Attributes())
                                {
                                    switch (att.Name.ToString())
                                    {
                                        case "id":
                                            stationId = att.Value;
                                            break;
                                        case "cars":
                                            carCap = int.Parse(att.Value);
                                            break;
                                        case "latitude":
                                            latitude = Double.Parse(att.Value);
                                            break;
                                        case "longitude":
                                            longitude = Double.Parse(att.Value);
                                            break;
                                    }
                                }
                                Node temp = new Node()
                                {
                                    Name = name,
                                    StationCode = stationId,
                                    Location = new Point() { Latitude = latitude, Longitude = longitude },
                                    CarCapacity = carCap,
                                    InLinks = new List<Link>(),
                                    OutLinks = new List<Link>(),
                                    InOrders = new List<Order>(),
                                    OutOrders = new List<Order>(),
                                };
                                nodeCurAdjMap[temp] = GeocodingEngine.getInstance()
                                    .LocationConvertToUSD(temp.Location, 1.0);
                                nodes.Add(temp);
                            }
                            break; //end Nodes
                            case "Arcs":
                            foreach (XElement e in el.Elements())
                            {
                                string to ="", from ="";
                                double track_mult = 0, fuel_adj =0;
                                int max_trains = 0;
                                foreach (XAttribute att in e.Attributes())
                                {
                                    switch (att.Name.ToString())
                                    {
                                        case "end":
                                            to = att.Value;
                                            break;

                                        case "start":
                                            from = att.Value;
                                            break;
                                        case "trackMultiplier":
                                            track_mult = Double.Parse(att.Value);
                                            break;
                                        case "maxTrains":
                                            max_trains = Int32.Parse(att.Value);
                                            break;
                                        case "fuelAdj":
                                            fuel_adj = Double.Parse(att.Value);
                                            break;
                                    }
                                }
                                int toIndex = -1;
                                int fromIndex = -1;
                                int k = 0;
                                foreach (Node n in nodes)
                                {
                                    if (toIndex >= 0 && fromIndex >= 0)
                                        break;
                                    if (n.StationCode.Equals(to))
                                        toIndex = k;
                                    if (n.StationCode.Equals(from))
                                        fromIndex = k;
                                    k++;
                                }
                                Link tempLink = new Link
                                {
                                    From = nodes[fromIndex],
                                    To = nodes[toIndex],
                                    MaxTrains = max_trains,
                                    FuelAdjustment = fuel_adj,
                                };
                                tempLink.Distance = GeocodingEngine.getInstance().Distance(
                                    tempLink.From.Location,
                                    tempLink.To.Location
                                ) * track_mult;
                                nodes[fromIndex].OutLinks.Add(tempLink);
                                nodes[toIndex].InLinks.Add(tempLink);
                                links.Add(tempLink);
                            }
                        break; //end arcs
                        }
                    }
                    break; //end network
                    case "Orders":
                    foreach (XElement el in element.Elements())
                    {
                        string id ="", origin ="", dest ="";
                        int cars = 0;
                        double revenue = 0;
                        foreach (XAttribute att in el.Attributes())
                        {
                            switch(att.Name.ToString())
                            {
                                case "cars":
                                    cars = int.Parse(att.Value);
                                    break;
                                case "revenue":
                                    revenue = Double.Parse(att.Value);
                                    break;
                                case "to":
                                    dest = att.Value;
                                    break;
                                case "from":
                                    origin = att.Value;
                                    break;
                            }
                        }
                        int destIndex = -1;
                        int origIndex = -1;
                        int k = 0;
                        foreach (Node n in nodes)
                        {
                            if (destIndex >= 0 && origIndex >= 0)
                                break;
                            if(n.StationCode.Equals(dest))
                                destIndex = k;
                            if(n.StationCode.Equals(origin))
                                origIndex = k;
                            k++;
                        }
                        Order tempOrder = new Order { Cars = cars,
                            Destination = nodes[destIndex], Origin = nodes[origIndex],
                            //XMLOrderID =
                        };
                        tempOrder.Revenue = nodeCurAdjMap[tempOrder.Origin] * revenue;
                        nodes[origIndex].OutOrders.Add(tempOrder);
                        nodes[destIndex].InOrders.Add(tempOrder);
                        orders.Add(tempOrder);

                    }
                    break; //end orders
                }
            }

            var network = new Network{ CarCostPerMile = carCost,
                FuelCostPerMile = fuelCost, NonFuelCostPerMile = nonFuelCost,
                MaxCarsPerTrain = maxCars, Links = links,
                Nodes = nodes, Orders = orders,
                OptimizationResult = null};

            return network;
        }
Beispiel #4
0
        /// <summary>
        /// Clones this network, creating new nodes, links, orders, etc.
        /// Does NOT copy the ID
        /// </summary>
        public object Clone()
        {
            Network net = new Network()
            {
                Author = Author,
                MaxCarsPerTrain = MaxCarsPerTrain,
                NonFuelCostPerMile = NonFuelCostPerMile,
                FuelCostPerMile = FuelCostPerMile,
                CarCostPerMile = CarCostPerMile,
            };

            if(OptimizationResult != null)
            {
                net.OptimizationResult = (Optimization)OptimizationResult.Clone();
                net.OptimizationResult.OptimizedNetwork = net;
            }

            // Copying nodes a bit more complicated so do it outside primitive cloning.
            // Make a mapping for old nodes to new nodes, for easy translation on links and orders.
            var oldToNewNodes = new Dictionary<Node, Node>();
            var oldToNewLinks = new Dictionary<Link, Link>();

            net.Nodes = Nodes.Select(n =>
                {
                    Node newN = (Node)n.Clone();
                    oldToNewNodes.Add(n, newN);
                    return newN;
                }).ToList();

            net.Links = Links.Select(l =>
                {
                    Link newL = (Link)l.Clone();
                    newL.From = oldToNewNodes[l.From];
                    newL.To = oldToNewNodes[l.To];

                    oldToNewNodes[l.From].OutLinks.Add(newL);
                    oldToNewNodes[l.To].InLinks.Add(newL);

                    oldToNewLinks.Add(l, newL);

                    return newL;
                }).ToList();

            net.Orders = Orders.Select(l =>
                {
                    Order newO = (Order)l.Clone();
                    newO.Origin = oldToNewNodes[l.Origin];
                    newO.Destination = oldToNewNodes[l.Destination];

                    oldToNewNodes[l.Origin].OutOrders.Add(newO);
                    oldToNewNodes[l.Destination].InOrders.Add(newO);

                    return newO;
                }).ToList();

            // Copy over the cloned optimization if it exists.
            if(OptimizationResult != null)
            {
                net.OptimizationResult = (Optimization)OptimizationResult.Clone();
                net.OptimizationResult.Nodes = OptimizationResult.Nodes.Select(n => {
                    NodeOptimized newNO = (NodeOptimized)n.Clone();
                    newNO.Node = oldToNewNodes[n.Node];
                    return newNO;
                }).ToList();
                net.OptimizationResult.Links = OptimizationResult.Links.Select(l => {
                    LinkOptimized newLO = (LinkOptimized)l.Clone();
                    newLO.Link = oldToNewLinks[l.Link];
                    return newLO;
                }).ToList();
            }

            return net;
        }
        public ActionResult CreateBlank(string NetworkName)
        {
            var nvm = new NetworkListViewModel();

            if(NetworkName == "")
            {
                ViewBag.UploadAlert = "Enter a network name";

                using (var c = new DataModelContext())
                {
                    nvm.Networks = c.Networks.Include("Author").Where(n => n.Name != null).ToList();
                }
                return View("Index", nvm);
            }

            using(var c = new DataModelContext())
            {
                var xmlnetwork = new Network();

                xmlnetwork.Name = NetworkName;
                xmlnetwork.Author = UserDataEngine.getInstance().GetCurrentUser(c, HttpContext);
                xmlnetwork.LastEdit = DateTime.Now;
                c.Networks.Add(xmlnetwork);

                try
                {
                    c.SaveChanges();
                }
                catch(DbEntityValidationException e)
                {
                    foreach(var i in e.EntityValidationErrors)
                    {
                        Console.WriteLine(i.ValidationErrors);
                    }
                    throw e;
                }
                nvm.Networks = c.Networks.Include("Author").Where(n => n.Name != null).ToList();

                ViewBag.NewNetworkID = xmlnetwork.ID;
            }

            ViewBag.Alert = "Network upload successful";
            ViewBag.AlertClass = "alert-success";
            return View("Index", nvm);
        }
        public RawOptimizedState Optimize(
			Network net,
			OptimizationOptions options)
        {
            var context = SolverContext.GetContext();
            context.ClearModel();
            var model = context.CreateModel();

            // Load in nodes, links, orders as lists.
            var nodes = net.Nodes.ToList();
            var links = net.Links.ToList();
            var orders = net.Orders.ToList();

            // Make sure the existing optimization has default weights set.
            if(options.AllowLocomotiveCapacityExpansion)
            {
                if(net.OptimizationResult.DefaultLinkExpansion == null)
                {
                    net.OptimizationResult.DefaultLinkExpansion = new ExpansionParameters()
                    {
                        CapacityExpansionMaxPossible = 100,
                        CapacityExpansionCostPerUnit = 10000
                    };
                }
            }
            if(options.AllowNodeCapacityExpansion)
            {
                if(net.OptimizationResult.DefaultNodeExpansion == null)
                {
                    net.OptimizationResult.DefaultNodeExpansion = new ExpansionParameters()
                    {
                        CapacityExpansionMaxPossible = 10000,
                        CapacityExpansionCostPerUnit = 1000
                    };
                }
            }

            #region Decision variables, car costs
            var flowDecisions = new Dictionary<Node,Dictionary<Link,Decision>>();
            Term totalCarCosts = 0;

            var expandNodeDecisions = new Dictionary<NodeOptimized,Decision>();
            var expandLinkDecisions = new Dictionary<LinkOptimized,Decision>();
            Term totalExpandCosts = 0;

            // One per link for each node.
            foreach(var node in nodes)
            {
                flowDecisions[node] = new Dictionary<Link,Decision>();
                foreach(var link in links)
                {
                    flowDecisions[node][link] = new Decision(
                        Domain.IntegerNonnegative,
                        "Node_" + node.ID + "_cars_" +
                        link.From.ID + "_to_" + link.To.ID
                    );

                    model.AddDecision(flowDecisions[node][link]);

                    // Car cost for this link.
                    totalCarCosts += flowDecisions[node][link] * link.Distance * net.CarCostPerMile;
                }
            }
            // Create the decision vars for expansion, if necessary.
            if(options.AllowNodeCapacityExpansion)
            {
                foreach(var node in net.OptimizationResult.Nodes)
                {
                    expandNodeDecisions[node] = new Decision(
                        Domain.IntegerNonnegative,
                        "Node_" + node.Node.ID + "_expansion"
                    );

                    model.AddDecision(expandNodeDecisions[node]);

                    if(node.Expansion == null)
                        node.Expansion = new ExpansionParameters();

                    var perUnitCost = node.Expansion.CapacityExpansionCostPerUnit ??
                        (int)net.OptimizationResult.DefaultNodeExpansion.CapacityExpansionCostPerUnit;
                    int maxPossible = node.Expansion.CapacityExpansionMaxPossible ??
                        (int)net.OptimizationResult.DefaultNodeExpansion.CapacityExpansionMaxPossible;

                    totalExpandCosts += expandNodeDecisions[node] * perUnitCost;

                    model.AddConstraint("Node_exp_cap_" + node.Node.ID,
                        expandNodeDecisions[node] <= maxPossible);
                }
            }
            if(options.AllowLocomotiveCapacityExpansion)
            {
                foreach(var link in net.OptimizationResult.Links)
                {
                    expandLinkDecisions[link] = new Decision(
                        Domain.IntegerNonnegative,
                        "Link_" + link.Link.ID + "_expansion"
                    );

                    model.AddDecision(expandLinkDecisions[link]);

                    if(link.Expansion == null)
                        link.Expansion = new ExpansionParameters();

                    var perUnitCost = link.Expansion.CapacityExpansionCostPerUnit ??
                        (int)net.OptimizationResult.DefaultLinkExpansion.CapacityExpansionCostPerUnit;
                    int maxPossible = link.Expansion.CapacityExpansionMaxPossible ??
                        (int)net.OptimizationResult.DefaultLinkExpansion.CapacityExpansionMaxPossible;

                    totalExpandCosts += expandLinkDecisions[link] * perUnitCost;

                    model.AddConstraint("Link_exp_cap_" + link.Link.ID,
                        expandLinkDecisions[link] <= maxPossible);
                }
            }
            #endregion

            #region Locomotive decision variables, locomotive costs
            Term totalLocomotiveCosts = 0;
            var locomotiveDecisions = new Dictionary<Link, Decision>();
            foreach(var link in links)
            {
                locomotiveDecisions[link] = new Decision(Domain.IntegerNonnegative,
                    "Locomotives_" + link.From.ID + "_to_" + link.To.ID);
                model.AddDecision(locomotiveDecisions[link]);

                // Constraint on max locomotives.
                // If optimized, number of locomotives is allowed to be below the capacity.
                Term locos = locomotiveDecisions[link];
                if(options.AllowLocomotiveCapacityExpansion)
                {
                    Decision expand = expandLinkDecisions.FirstOrDefault(
                        l => l.Key.Link == link
                    ).Value;

                    model.AddConstraint("Maxloco_" + link.From.ID + "_to_" + link.To.ID,
                        locos <= link.MaxTrains + expand);
                }
                else
                {
                    model.AddConstraint("Maxloco_" + link.From.ID + "_to_" + link.To.ID,
                        locos <= link.MaxTrains);
                }

                Term locoCost = link.Distance * locomotiveDecisions[link]
                    * (net.NonFuelCostPerMile + net.FuelCostPerMile * link.FuelAdjustment);
                totalLocomotiveCosts += locoCost;
            }
            #endregion

            #region Constraint 1: Order Flow
            // For loop so that indices are kept.
            foreach(var fulfiller in nodes)
            {
                foreach(var fulfilled in nodes)
                {
                    var fulfilledOrders = orders.Where(o => o.Origin == fulfiller);
                    if(fulfilled != fulfiller)
                        fulfilledOrders = fulfilledOrders.Where(o => o.Destination == fulfilled);

                    // Required flow on nodeFulfilled to satisfy the order.
                    int requiredFlow = 0;
                    foreach(Order order in fulfilledOrders)
                    {
                        if(fulfilled == fulfiller)
                            requiredFlow += order.Cars;
                        else
                            requiredFlow -= order.Cars;
                    }

                    // Sum of decision variables that should match the required flow.
                    Term actualFlow = 0;
                    // Get links that go to and from fulfilled.
                    var fromLinks = links.Where(l => l.From == fulfilled);
                    var toLinks = links.Where(l => l.To == fulfilled);
                    // Go through related decision variables.
                    foreach(var link in fromLinks)
                    {
                        // Decision variable index.
                        actualFlow += flowDecisions[fulfiller][link];
                    }
                    foreach(var link in toLinks)
                    {
                        // Decision variable index.
                        actualFlow -= flowDecisions[fulfiller][link];
                    }

                    model.AddConstraint("_" + fulfiller.ID + "_fulfilling_" + fulfilled.ID,
                        actualFlow == requiredFlow);
                }
            }
            #endregion

            #region Constraint 2: Link Capacity
            foreach(var link in links)
            {
                // Total amount of flow over this link, summed for all car sources.
                Term totalFlow = 0;

                foreach(var node in nodes)
                {
                    totalFlow += flowDecisions[node][link];
                }

                Term linkCapacity = locomotiveDecisions[link] * net.MaxCarsPerTrain;
                if(options.AllowLocomotiveCapacityExpansion)
                {
                    LinkOptimized optNode = net.OptimizationResult.Links.Where(n => n.Link == link).First();
                    // If the user has set max possible expansions for flow in or out, use them.

                    model.AddConstraint("Link_" + link.ID + "_cap",
                        totalFlow <= linkCapacity + expandLinkDecisions[optNode]);
                }
                else
                {
                    model.AddConstraint("Link_" + link.ID + "_cap",
                        totalFlow <= linkCapacity);
                }
            }
            #endregion

            #region Constraint 3/4: Node Capacity
            foreach(var node in nodes)
            {
                // Get all in and out links.
                var outLinks = links.Where(l => l.From == node);
                var inLinks = links.Where(l => l.To == node);

                Term flowOut = 0;
                Term flowIn = 0;

                foreach(var nodeo in nodes)
                {
                    foreach(var link in outLinks)
                        flowOut += flowDecisions[nodeo][link];
                    foreach(var link in inLinks)
                        flowIn += flowDecisions[nodeo][link];
                }

                if(options.AllowNodeCapacityExpansion)
                {
                    NodeOptimized optNode = net.OptimizationResult.Nodes.Where(n => n.Node == node).First();
                    // If the user has set max possible expansions for flow in or out, use them.

                    model.AddConstraint("Node_" + node.ID + "_capacity_out",
                        flowOut <= node.CarCapacity + expandNodeDecisions[optNode]);
                    model.AddConstraint("Node_" + node.ID + "_capacity_in",
                        flowIn <= node.CarCapacity + expandNodeDecisions[optNode]);
                    // If there is no max, make no constraint.
                }
                else
                {
                    model.AddConstraint("Node_" + node.ID + "_capacity_out",
                        flowOut <= node.CarCapacity);
                    model.AddConstraint("Node_" + node.ID + "_capacity_in",
                        flowIn <= node.CarCapacity);
                }
            }
            #endregion

            #region Objective Function
            // Objective function. (Minimize)
            Term totalCost = totalCarCosts + totalLocomotiveCosts + totalExpandCosts;
            model.AddGoal("TotalCost", GoalKind.Minimize, totalCost);
            #endregion

            //Directive directive = new LpSolveDirective();
            //Directive directive = new SimplexDirective();
            Directive directive = new GurobiDirective();
            //Directive directive = new MixedIntegerProgrammingDirective();

            directive.TimeLimit = TIMEOUT_MAX_SECONDS * 1000;

            var solution = context.Solve(directive);

            var extractedFlowDec = new Dictionary<Node, Dictionary<Link, int>>();
            var extractedLocoDec = new Dictionary<Link, int>();

            foreach(var nvp in flowDecisions)
            {
                extractedFlowDec[nvp.Key] = new Dictionary<Link,int>();
                foreach(var lvp in nvp.Value)
                {
                    extractedFlowDec[nvp.Key][lvp.Key] = (int)lvp.Value.ToDouble();
                }
            }
            foreach(var lvp in locomotiveDecisions)
            {
                extractedLocoDec[lvp.Key] = (int)lvp.Value.ToDouble();
            }

            foreach(var nvp in expandNodeDecisions)
            {
                nvp.Key.ExpansionSuggested = (int)nvp.Value.ToDouble();
            }
            foreach(var lvp in expandLinkDecisions)
            {
                lvp.Key.ExpansionSuggested = (int)lvp.Value.ToDouble();
            }

            // Extract the suggestion cost. (Don't know a better way to do this.)
            double suggestionCapitalCost = 0.0;

            if(options.AllowNodeCapacityExpansion)
            {
                foreach(var node in net.OptimizationResult.Nodes)
                {
                    var perUnitCost = node.Expansion.CapacityExpansionCostPerUnit ??
                        (int)net.OptimizationResult.DefaultNodeExpansion.CapacityExpansionCostPerUnit;

                    suggestionCapitalCost += expandNodeDecisions[node].ToDouble() * perUnitCost;
                }
            }
            if(options.AllowLocomotiveCapacityExpansion)
            {
                foreach(var link in net.OptimizationResult.Links)
                {
                    var perUnitCost = link.Expansion.CapacityExpansionCostPerUnit ??
                        (int)net.OptimizationResult.DefaultLinkExpansion.CapacityExpansionCostPerUnit;

                    suggestionCapitalCost += expandLinkDecisions[link].ToDouble() * perUnitCost;
                }
            }

            RawOptimizedState.RawQuality q;
            switch(solution.Quality)
            {
                case SolverQuality.Optimal:
                    q = RawOptimizedState.RawQuality.Solved;
                    break;

                case SolverQuality.Infeasible:
                    q = RawOptimizedState.RawQuality.Infeasible;
                    break;

                case SolverQuality.InfeasibleOrUnbounded:
                case SolverQuality.Unbounded:
                    q = RawOptimizedState.RawQuality.Unbounded;
                    break;

                case SolverQuality.Unknown:
                case SolverQuality.Feasible:
                default:
                    q = RawOptimizedState.RawQuality.TimedOut;
                    break;
            }
            var rawState = new RawOptimizedState()
            {
                solvedNetwork = net,
                flowDecisions = extractedFlowDec,
                locomotiveDecisions = extractedLocoDec,
                totalCost = (int)(model.Goals.First().ToDouble() - suggestionCapitalCost),
                suggestionCapitalCost = (int)suggestionCapitalCost,
                Quality = q
            };

            return rawState;
        }