private static void CreateRooms(HostelAllocationDTO hostelAllocation, int hostelCapacity)
        {
            var random = new Random();

            hostelAllocation.NumRooms = random.Next(5, 10);
            List <int> roomsCapacity = new List <int>();

            for (var room = 0; room < hostelAllocation.NumRooms; room++)
            {
                if (room != hostelAllocation.NumRooms - 1)
                {
                    var hostelActualCapacity = roomsCapacity.Sum();
                    var maxRoomSize          = hostelCapacity - hostelActualCapacity > 10 + hostelAllocation.NumRooms - room ?
                                               10 : hostelCapacity - hostelActualCapacity - hostelAllocation.NumRooms + room + 1;
                    var roomSize = random.Next(1, maxRoomSize);
                    roomsCapacity.Add(roomSize);
                }
                else
                {
                    var freeSpaces = hostelCapacity - roomsCapacity.Sum();
                    var roomSize   = freeSpaces > 10 ? 10 : freeSpaces;
                    roomsCapacity.Add(roomSize);
                }
            }

            hostelAllocation.RoomCapacity = roomsCapacity.ToArray();
        }
        public static HostelAllocationDTO CreateRandomTest(string fileName)
        {
            Dictionary <int, int> groupsSizes      = new Dictionary <int, int>();
            HostelAllocationDTO   hostelAllocation = new HostelAllocationDTO();

            hostelAllocation.InitialAllocation = new List <Tuple <int, int> >();
            hostelAllocation.GroupsDemands     = new List <Tuple <int, int> >();

            var random = new Random();

            hostelAllocation.NumDays = random.Next(10, 20);
            //hostelAllocation.NumDays = 10;
            int hostelCapacity = random.Next(20, 50);

            //int hostelCapacity = 30;

            CreateRooms(hostelAllocation, hostelCapacity);

            hostelCapacity = hostelAllocation.RoomCapacity.Sum();

            SetInitialHostelAllocation(groupsSizes, hostelAllocation);

            for (var day = 1; day <= hostelAllocation.NumDays; day++)
            {
                DesallocateGroupsByDay(hostelAllocation, groupsSizes, day);
                var dailyAllocatedGroups   = hostelAllocation.GroupsDemands.Where(d => d.Item2 == day).Select(d => d.Item1).ToList();
                int actualHostelCapacicity = dailyAllocatedGroups.Select(g => groupsSizes[g]).Sum();

                while (actualHostelCapacicity < hostelCapacity)
                {
                    int groupIndex             = groupsSizes.Count;
                    var actualHostelAllocation = hostelAllocation.GroupsDemands.Where(g => g.Item2 == day).Select(g => groupsSizes[g.Item1]).Sum();
                    var maxGroupSize           = hostelCapacity - actualHostelAllocation > 10 ? 10 : hostelCapacity - actualHostelAllocation;
                    if (maxGroupSize >= 1)
                    {
                        var groupSize = random.Next(1, maxGroupSize);
                        groupsSizes.Add(groupIndex, groupSize);
                        hostelAllocation.GroupsDemands.Add(new Tuple <int, int>(groupIndex, day));
                        actualHostelCapacicity += groupSize;
                    }
                }
            }
            hostelAllocation.GroupsSizes = groupsSizes.Select(g => g.Value).ToArray();

            using (StreamWriter file = File.CreateText(@"C:\\Users\\alanw\\OneDrive\\Documentos\\GitHub\\HostelAllocation\\HostelAllocationOptimization\\bin\\Debug\\netcoreapp2.0\\" + fileName))
            {
                JsonSerializer serializer = new JsonSerializer();
                serializer.Serialize(file, hostelAllocation);
            }

            return(hostelAllocation);
        }
        private static void DesallocateGroupsByDay(HostelAllocationDTO hostelAllocation, Dictionary <int, int> groupsSizes, int day)
        {
            var random = new Random();
            var previousGroupsAllocated = hostelAllocation.GroupsDemands.Where(d => d.Item2 == day - 1).Select(d => d.Item1).ToList();
            var numGroupsToLeft         = random.Next(0, previousGroupsAllocated.Count);

            for (var i = 0; i < numGroupsToLeft; i++)
            {
                var groupToLeft = random.Next(0, previousGroupsAllocated.Count - 1);
                previousGroupsAllocated.RemoveAt(groupToLeft);
            }
            foreach (var group in previousGroupsAllocated)
            {
                hostelAllocation.GroupsDemands.Add(new Tuple <int, int>(group, day));
            }
        }
 public List <DailyRoomAllocation> Post([FromBody] HostelAllocationDTO hostelAllocation)
 {
     return(HostelAllocationOptimizer.Optimize(hostelAllocation));
 }
Exemple #5
0
        public static List <DailyRoomAllocation> Optimize(HostelAllocationDTO hostelAllocation)
        {
            try
            {
                int   numDays      = hostelAllocation.NumDays;
                int   numRooms     = hostelAllocation.NumRooms;
                int   numGroups    = hostelAllocation.GroupsSizes.Count();
                int[] groupSize    = hostelAllocation.GroupsSizes;
                int[] roomCapacity = hostelAllocation.RoomCapacity;

                List <Tuple <int, int> > groupsDemands = new List <Tuple <int, int> >(); // groupsDemands(group, day)
                groupsDemands = hostelAllocation.GroupsDemands;
                // Group 0
                //groupsDemands.Add(new Tuple<int, int>(0, 0));
                //groupsDemands.Add(new Tuple<int, int>(0, 1));
                //groupsDemands.Add(new Tuple<int, int>(0, 2));
                //// Group 1
                //groupsDemands.Add(new Tuple<int, int>(1, 0));
                //groupsDemands.Add(new Tuple<int, int>(1, 1));
                //// Group 2
                //groupsDemands.Add(new Tuple<int, int>(2, 0));
                //groupsDemands.Add(new Tuple<int, int>(2, 1));
                //groupsDemands.Add(new Tuple<int, int>(2, 2));
                //// Group 3
                //groupsDemands.Add(new Tuple<int, int>(3, 1));
                //groupsDemands.Add(new Tuple<int, int>(3, 2));
                //// Group 4
                //groupsDemands.Add(new Tuple<int, int>(4, 1));
                //groupsDemands.Add(new Tuple<int, int>(4, 2));
                //// Group 5
                //groupsDemands.Add(new Tuple<int, int>(5, 1));
                //groupsDemands.Add(new Tuple<int, int>(5, 2));
                //// Group 6
                //groupsDemands.Add(new Tuple<int, int>(6, 2));

                List <Tuple <int, int> > initialAllocation = new List <Tuple <int, int> >(); // initialAlocation<group, room>
                initialAllocation = hostelAllocation.InitialAllocation;
                //initialAllocation.Add(new Tuple<int, int>(0, 0));
                //initialAllocation.Add(new Tuple<int, int>(1, 1));
                //initialAllocation.Add(new Tuple<int, int>(2, 2));

                GRBEnv   env   = new GRBEnv("hostel.log");
                GRBModel model = new GRBModel(env);

                model.ModelName = "hostel";

                //variável de decisão: xijk - se o grupo i está no quyarto j no dia k
                GRBVar[,,] x = new GRBVar[numGroups, numRooms, numDays];
                for (int i = 0; i < numGroups; i++)
                {
                    for (int j = 0; j < numRooms; j++)
                    {
                        for (int k = 0; k < numDays; k++)
                        {
                            x[i, j, k] = model.AddVar(0, 1, 0, GRB.BINARY, "Grupo " + x + " quarto " + j + " dia " + k);
                        }
                    }
                }

                //Initialize Rooms with initial alocation
                foreach (var alocation in initialAllocation)
                {
                    x[alocation.Item1, alocation.Item2, 0].Set(GRB.DoubleAttr.LB, 1);
                }

                //variável de decisão: yik - se o grupo i mudou de quarto no dia k
                GRBVar[,] y = new GRBVar[numGroups, numDays];
                for (int i = 0; i < numGroups; i++)
                {
                    for (int k = 0; k < numDays; k++)
                    {
                        y[i, k] = model.AddVar(0, 1, 0, GRB.BINARY, "Grupo " + i + " mudou quarto no dia " + k);
                    }
                }

                //Restrição 1: capacidade do quarto
                for (int j = 0; j < numRooms; j++)
                {
                    for (int k = 0; k < numDays; k++)
                    {
                        GRBLinExpr roomAlocation = 0.0;
                        for (int i = 0; i < numGroups; i++)
                        {
                            roomAlocation.AddTerm(groupSize[i], x[i, j, k]);
                        }
                        model.AddConstr(roomAlocation <= roomCapacity[j], "Capacity room " + j);
                    }
                }

                //Restrição 2: todo grupo deverá estar alocado em algum quarto nos dias que demandou
                for (int i = 0; i < numGroups; i++)
                {
                    for (int k = 0; k < numDays; k++)
                    {
                        GRBLinExpr demGroup = 0.0;
                        if (groupsDemands.Any(d => d.Item1 == i && d.Item2 == k))
                        {
                            for (int j = 0; j < numRooms; j++)
                            {
                                demGroup.AddTerm(1, x[i, j, k]);
                            }
                            model.AddConstr(demGroup == 1, "Alocação grupo " + i + " no dia " + k);
                        }
                    }
                }

                //Restrição 3: se o grupo i tivesse no quarto j no dia k e no dia k + 1 ele não estiver, ele mudou de quarto
                for (int i = 0; i < numGroups; i++)
                {
                    for (int j = 0; j < numRooms; j++)
                    {
                        for (int k = 0; k < numDays - 1; k++)
                        {
                            if (k == 0 && initialAllocation.Any(d => d.Item1 == i) && groupsDemands.Any(d => d.Item1 == i && d.Item2 == k + 1))
                            {
                                model.AddConstr((1 - x[i, j, k]) + x[i, j, k + 1] + y[i, k] >= 1, "Grupo " + i + " mudou de quarto dia " + k);
                            }
                            else if (groupsDemands.Any(d => d.Item1 == i && d.Item2 == k) && groupsDemands.Any(d => d.Item1 == i && d.Item2 == k + 1))  // O grupo tem demanda para o dia seguinte
                            {
                                model.AddConstr((1 - x[i, j, k]) + x[i, j, k + 1] + y[i, k] >= 1, "Grupo " + i + " mudou de quarto dia " + k);
                            }
                        }
                    }
                }

                model.ModelSense = GRB.MINIMIZE;

                GRBLinExpr obj = 0;
                for (int i = 0; i < numGroups; i++)
                {
                    for (int k = 0; k < numDays; k++)
                    {
                        obj.AddTerm(groupSize[i], y[i, k]);
                    }
                }
                model.SetObjective(obj, GRB.MINIMIZE);

                // Optimize model
                model.Optimize();

                if (model.Status == GRB.Status.INFEASIBLE)
                {
                    throw new Exception("Infeasible model");
                }

                var allocation      = ListDailyGroupsAllocation(x, y, model.ObjVal);
                var roomsAllocation = ListDailyRoomAllocation(x, y, model.ObjVal);

                // Dispose of model and env
                model.Dispose();
                env.Dispose();

                return(roomsAllocation);
            }

            catch (GRBException e)
            {
                throw;
                //Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
            }
        }
        private static void SetInitialHostelAllocation(Dictionary <int, int> groupsSizes, HostelAllocationDTO hostelAllocation)
        {
            var random               = new Random();
            var firstDayAllocation   = random.Next(hostelAllocation.RoomCapacity.Sum() / 10, hostelAllocation.RoomCapacity.Sum());
            var availableRoomsSpaces = hostelAllocation.RoomCapacity
                                       .Select(r => r - hostelAllocation.InitialAllocation.Where(i => i.Item2 == r).Select(i => groupsSizes[i.Item1]).Sum()).ToList();

            while (firstDayAllocation > 0 && availableRoomsSpaces.Sum() >= firstDayAllocation && availableRoomsSpaces.Any(room => room > 0))
            {
                var allocatedRooms  = hostelAllocation.InitialAllocation.ToList();
                var randomGroupSize = random.Next(1, availableRoomsSpaces.Max() - 1);
                var room            = availableRoomsSpaces.Where(r => r >= randomGroupSize).First();
                var roomIndex       = availableRoomsSpaces.IndexOf(room);
                var group           = groupsSizes.Count;
                groupsSizes.Add(group, randomGroupSize);
                hostelAllocation.InitialAllocation.Add(new Tuple <int, int>(group, roomIndex));
                availableRoomsSpaces[roomIndex] -= randomGroupSize;
                firstDayAllocation -= randomGroupSize;
                //availableRoomsSpaces = hostelAllocation.RoomCapacity
                //    .Select(r => r - hostelAllocation.InitialAllocation.Where(i => i.Item2 == r).Select(i => groupsSizes[i.Item1]).Sum()).ToList();
            }
        }
 private static int DailyAllocation(HostelAllocationDTO hostelAllocation, int day)
 {
     return(hostelAllocation.GroupsDemands.Where(g => g.Item2 == day).Select(g => g.Item1).Sum());
 }