示例#1
0
    public void Run()
    {
        var api = new ApiHelper <Ivr8.SolveRequest, Ivr8.SolutionResponse>("ivr8-yni1c9k2swof", configFile);

        // so here we're going to build the model

        // create a solve request
        Ivr8.SolveRequest sr = new Ivr8.SolveRequest();

        sr.Model = new Ivr8.Model(); // initialise the model container

        // see ivr7 basic examples for notes around each of these methods.
        // the ivr7/8 models are interchangeable, except that the IVR8 model supports
        // compartment modelling.
        ivr8helper.makeDistanceTimeCapDims(sr.Model); // adds distance, time & capacity
        ivr8helper.makeLocations(sr.Model, data);     // adds all the locations to the model
        ivr8helper.makeJobTimeCap(sr.Model, data, ivr8helper.Rep(0, data.Count - 1), ivr8helper.Seq(1, data.Count));
        sr.Model.vehicleCostClasses.Add(ivr8helper.makeVccSimple("vcc1", 1000, 0.01f, 0.01f, 0.01f, 1, 3));
        sr.Model.vehicleClasses.Add(ivr8helper.makeVcSimple("vc1", 1, 1, 1, 1));
        sr.Model.Vehicles.Add(ivr8helper.makeVehicleCap("vehicle_0", // 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
                                                        ));

        // lets pretend for a moment that we have a vehicle which is layed out as follows:
        //  Top Rack    [ ] [ ] [ ] [ ]  100kg per "compartment"  c1, c2, c3, c4
        //  Lower Rack  [ ] [ ] [ ] [ ]  400kg per "compartment"  c5, c6, c7, c8
        // 100*4 + 400*4 // adds up to the 2 ton total limit on a vehicle (if every compartment could be filled to max)

        for (int i = 0; i < 8; i++)
        {
            sr.Model.Compartments.Add(
                new Ivr8.Compartment
            {
                Id         = "c" + (i + 1),
                Capacities =
                {
                    new Ivr8.Compartment.Capacity {
                        dimensionId = "capacity",
                        capacity    = i < 4 ? 100 : 400 // switch between top and bottom rack
                    }
                }
            });
        }
        // now we can define a compartment set (a container for the individual compartments)
        // which is attached to a vehicle.
        var cset = new Ivr8.CompartmentSet
        {
            Id = "double-decker"
        };

        foreach (var c in sr.Model.Compartments)
        {
            cset.compartmentIds.Add(c.Id); // add all the defined compartments to the model
        }
        sr.Model.compartmentSets.Add(cset);

        // then we assign the "double-decker" compartment set to the vehicle class.
        // we could have added it to each vehicle if we wanted, this is simply easier.
        sr.Model.vehicleClasses[0].compartmentSetId = "double-decker";

        sr.solveType = Ivr8.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)

        ivr8helper.printSolution(Solution, true, false, false, false);
        ivr8helper.printCompartmentSummary(sr.Model, Solution);
        // okay, so what are we looking at here? So basically each "allocated" is when a task is executed
        // so either a pickup or a dropff. the capacity of each compartment is listed at the top under "capacity"
        // each stop shows where the volume is added and we can see that only one change is made at each node.
        // this is because the task is assigned to a compartment. At no point is the total volume allocated
        // to a compartment more than the capacity of the compartment. There are 16 allocations here because there
        // are 8 jobs, i.e. 8 pickups, 8 dropoffs. So after each pickup we can see the state of the load on
        // the vehicle. It's maximum weight is at stop.8 => 1800 units.


        // now lets try somethign that's infeasible (by design) and see what happens.
        // we're going to clear the compartments, populate a new list and run the model.
        sr.Model.Compartments.Clear();
        for (int i = 0; i < 8; i++)
        {
            sr.Model.Compartments.Add(
                new Ivr8.Compartment
            {
                Id         = "c" + (i + 1),
                Capacities =
                {
                    new Ivr8.Compartment.Capacity {
                        dimensionId = "capacity",
                        capacity    = i < 4 ? 150 : 350 // bottom rack is at 350 - which is less than the biggest order
                    }
                }
            });
        }
        requestId = api.Post(sr);       // send the model to the api
        Solution  = api.Get(requestId); // get the response (which it typed, so that's cool)
        ivr8helper.printSolution(Solution, false, false, false, true);
        ivr8helper.printCompartmentSummary(sr.Model, Solution);
        // ah, but the api is nice enough to tell us that there is no feasible compartment assignment
        // exists for this particular set of tasks as well as the constraining dimension (capacity).
        // The limit and value's are negative here indicating that the values aren't relevant.
        // if you're looking for a more informative error message, use the evaluate end-point which
        // can identify for a proposed sequence where things went wrong (or whether any feasible sub-set exists)


        // for visualisations see the R/python notebook for plots on the same example.
        return;
    }
    public void Run()
    {
        var api = new ApiHelper <Ivr8.SolveRequest, Ivr8.SolutionResponse>("ivr8-yni1c9k2swof", configFile);

        // so here we're going to build the model

        // create a solve request
        Ivr8.SolveRequest sr = new Ivr8.SolveRequest();

        sr.Model = new Ivr8.Model(); // initialise the model container

        // see ivr7 basic examples for notes around each of these methods.
        // the ivr7/8 models are interchangeable, except that the IVR8 model supports
        // compartment modelling.
        ivr8helper.makeDistanceTimeCapDims(sr.Model); // adds distance, time & capacity
        ivr8helper.makeLocations(sr.Model, data);     // adds all the locations to the model
        ivr8helper.makeJobTimeCap(sr.Model, data, ivr8helper.Rep(0, data.Count - 1), ivr8helper.Seq(1, data.Count));
        sr.Model.vehicleCostClasses.Add(ivr8helper.makeVccSimple("vcc1", 1000, 0.01f, 0.01f, 0.01f, 1, 3));
        sr.Model.vehicleClasses.Add(ivr8helper.makeVcSimple("vc1", 1, 1, 1, 1));
        sr.Model.Vehicles.Add(ivr8helper.makeVehicleCap("vehicle_0", // 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
                                                        ));

        //  We're going to simplify the config in this example slightly.
        //  Lower Rack  [ ] [ ] [ ] [ ]  500kg per "compartment"  c1, c2, c3, c4

        for (int i = 0; i < 4; i++)
        {
            sr.Model.Compartments.Add(
                new Ivr8.Compartment
            {
                Id         = "c" + (i + 1),
                Capacities =
                {
                    new Ivr8.Compartment.Capacity {
                        dimensionId = "capacity",
                        capacity    = 500
                    }
                }
            });
        }
        // now we can define a compartment set (a container for the individual compartments)
        // which is attached to a vehicle.
        var cset = new Ivr8.CompartmentSet
        {
            Id = "tanker"
        };

        foreach (var c in sr.Model.Compartments)
        {
            cset.compartmentIds.Add(c.Id); // add all the defined compartments to the model
        }

        sr.Model.compartmentSets.Add(cset);

        // now we can go back through the tasks and allocate them to allowable compartments
        // this is normal in fuel delivery systems where you have diesel/petrol constraints.
        // we're just going to decide on which jobs may go in which compartments based on the
        // index, and lets see if that's feasible. Obviously, you'll create it using proper logic
        // based on the business rules.

        Dictionary <string, HashSet <string> > allowableCompartments = new Dictionary <string, HashSet <string> >(); // just storing this for later

        for (int j = 0; j < sr.Model.Jobs.Count; j++)
        {
            var job = sr.Model.Jobs[j];
            job.compartmentRelations      = new Ivr8.Job.CompartmentRelation();
            job.compartmentRelations.type = Ivr8.Job.CompartmentRelation.Type.Inclusive;
            if (j % 2 == 0)
            {
                job.compartmentRelations.compartmentIds.Add("c2");
                job.compartmentRelations.compartmentIds.Add("c4");
                allowableCompartments.Add(job.Id, new HashSet <string> {
                    "c2", "c4"
                });
            }
            else
            {
                job.compartmentRelations.compartmentIds.Add("c1");
                job.compartmentRelations.compartmentIds.Add("c3");
                allowableCompartments.Add(job.Id, new HashSet <string> {
                    "c1", "c3"
                });
            }
        }

        sr.Model.vehicleClasses[0].compartmentSetId = "tanker";

        sr.solveType = Ivr8.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)

        ivr8helper.printSolution(Solution, true, false, false, false);
        ivr8helper.printCompartmentSummary(sr.Model, Solution);
        // so the compartment summary is nice - but it doesn't tell us whether we stuck to the constraints
        // around the relations for each of the jobs.

        // we can check against the "allowableCompartments" dictionary we created earlier here.
        foreach (var r in Solution.Routes)
        {
            foreach (var s in r.Stops)
            {
                if (s.compartmentId != "")
                {
                    // check if the job id is allowed to go on this compartment!
                    if (allowableCompartments.ContainsKey(s.jobId))
                    {
                        if (!allowableCompartments[s.jobId].Contains(s.compartmentId))
                        {
                            throw new Exception("Compartment assigned which wasn't in the inclusion list!");
                        }
                    }
                }
            }
        }
        // so that's nice, we can see that at each task assignment we only used compartments
        // which were in the allowable set we provided the api.
        // it's probably worth noting that the default is all compartments in a compartment-set are allowed
        // so you can either specify an inclusive sub-set, or excluded sub-set.
        // if all compartments are excluded then it will let you know that there's no feasible allocation



        // for visualisations see the R/python notebook for plots on the same example.
        return;
    }
    public void Run()
    {
        var api = new ApiHelper <Ivr8.SolveRequest, Ivr8.SolutionResponse>("ivr8-yni1c9k2swof", configFile);

        // so here we're going to build the model

        // create a solve request
        Ivr8.SolveRequest sr = new Ivr8.SolveRequest();

        sr.Model = new Ivr8.Model(); // initialise the model container

        // see ivr7 basic examples for notes around each of these methods.
        // the ivr7/8 models are interchangeable, except that the IVR8 model supports
        // compartment modelling.
        ivr8helper.makeDistanceTimeCapDims(sr.Model); // adds distance, time & capacity
        ivr8helper.makeLocations(sr.Model, data);     // adds all the locations to the model
        ivr8helper.makeJobTimeCap(sr.Model, data, ivr8helper.Rep(0, data.Count - 1), ivr8helper.Seq(1, data.Count));
        sr.Model.vehicleCostClasses.Add(ivr8helper.makeVccSimple("vcc1", 1000, 0.01f, 0.01f, 0.01f, 1, 3));
        sr.Model.vehicleClasses.Add(ivr8helper.makeVcSimple("vc1", 1, 1, 1, 1));
        sr.Model.Vehicles.Add(ivr8helper.makeVehicleCap("vehicle_0", // 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
                                                        ));

        // lets pretend for a moment that we have a vehicle which is layed out as follows:
        //  Top Rack    [ ] [ ] [ ] [ ]  100kg per "compartment"  c1, c2, c3, c4
        //  Lower Rack  [ ] [ ] [ ] [ ]  400kg per "compartment"  c5, c6, c7, c8
        // 100*4 + 400*4 // adds up to the 2 ton total limit on a vehicle (if every compartment could be filled to max)

        for (int i = 0; i < 8; i++)
        {
            sr.Model.Compartments.Add(
                new Ivr8.Compartment
            {
                Id         = "c" + (i + 1),
                Capacities =
                {
                    new Ivr8.Compartment.Capacity {
                        dimensionId = "capacity",
                        capacity    = i < 4 ? 100 : 400 // switch between top and bottom rack
                    }
                }
            });
        }
        // now we can define a compartment set (a container for the individual compartments)
        // which is attached to a vehicle.
        var cset = new Ivr8.CompartmentSet
        {
            Id = "double-decker"
        };

        foreach (var c in sr.Model.Compartments)
        {
            cset.compartmentIds.Add(c.Id); // add all the defined compartments to the model
        }

        // now we're going to add compartment relations which speak to the group limit.
        // we can create multiple group limits.
        // if we want something like, "the mass on the top may not exceed the mass on the bottom"
        var glim = new Ivr8.CompartmentSet.GroupLimit
        {
            dimensionId = "capacity",
            Limit       = 0
                          // so this says c1+c2+c3+c4-c5-c6-c7-c8 <= 0 is required for feasibility
                          // writing this differently c1:c4 - c5:c8 <= 0    (grouping the c's together)
                          // so c1:c4 <= c5:c8                              (moving c5:c8 to the rhs)
                          // which says the top rack (c1:c4) should sum to less than the bottom rack (c5:c8)
        };

        glim.Coefficients = new float[8];
        for (int i = 0; i < 8; i++)
        {
            glim.compartmentIds.Add("c" + (i + 1)); // adds c1:c8 to the equation.
            glim.Coefficients[i] = i < 4 ? +1 : -1; // sets the value in the array
        }

        cset.groupLimits.Add(glim);

        sr.Model.compartmentSets.Add(cset);

        // then we assign the "double-decker" compartment set to the vehicle class.
        // we could have added it to each vehicle if we wanted, this is simply easier.
        sr.Model.vehicleClasses[0].compartmentSetId = "double-decker";

        sr.solveType = Ivr8.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)

        ivr8helper.printSolution(Solution, true, false, false, false);
        ivr8helper.printCompartmentSummary(sr.Model, Solution);
        // In this table you can see that the the sum for compartments 1:4 is always less than 5:8
        // this way we're constrained by always having more weight on the bottom rack than the top
        // rack throughout the route (which is still pretty well costed)

        // for visualisations see the R/python notebook for plots on the same example.
        return;
    }