I've got an assignment in my Artificial Intelligence class.
It is a problem which we have to solve using Genetic Algorithms in R (using GA library). I'm looking for some ideas how to approach this.
Barbarians siege a city. General gives an order how many soldiers must guard a city wall on each hour during a day. This is his table:
Time of the day | Number of soldiers
00:00 - 01:00 150
01:00 - 02:00 160
02:00 - 03:00 160
03:00 - 04:00 170
04:00 - 05:00 350
05:00 - 06:00 380
06:00 - 07:00 400
07:00 - 08:00 420
08:00 - 09:00 450
09:00 - 10:00 470
10:00 - 11:00 500
11:00 - 12:00 500
12:00 - 13:00 450
13:00 - 14:00 350
14:00 - 15:00 300
15:00 - 16:00 300
16:00 - 17:00 310
17:00 - 18:00 350
18:00 - 19:00 350
19:00 - 20:00 330
20:00 - 21:00 300
21:00 - 22:00 250
22:00 - 23:00 200
23:00 - 24:00 170
Commander of defense wants the soldiers to be completely focused, when they are on patrol, so he gives this order:
Two of possible aproaches (so far):
Fitness function of GA would accept a number of solders and then perform a simulation:
Create a initial population (solders) and apply the rules from the commander in the fitness function (I don't really know how to define the above rules here) and then run GA until we get some useful score.
Since the assignment is over (yes, I go to the same class as OP) and this is an actually interesting problem, I'm posting my solution here:
library(GA)
Fitness <- function(x) {
x <- as.integer(x)
# z represents required soldiers at each hour
z <- c(150,160,160,170,350,380,400,420,450,470,500,500,450,350,300,300,310,350,350,330,300,250,200,170)
y <- rep(0,31)
for (i in 1:length(x)) {
y[i] <- y[i] + x[i]
y[i+1] <- y[i+1] + x[i]
y[i+2] <- y[i+2] + x[i]
y[i+3] <- y[i+3] + x[i]
#resting 4, 5
y[i+6] <- y[i+6] + x[i]
y[i+7] <- y[i+7] + x[i]
}
for (i in 1:7) {
y[i] <- y[i]+y[24+i]
}
y <- y[1:24]
p <- y >= z
if (FALSE %in% p) { return(-3000) }
return(-sum(x))
}
GA <- ga(type = "real-valued", fitness = Fitness, min = rep(0, 24), max = rep(150, 24), popSize = 24, suggestions = sol, maxiter = 5000, run = 5000, pmutation=0.9)
summary(GA)
sol <- (as.integer(GA@solution[1, ]))
sol
sum(sol)
The GA generates a vector of numbers of soldiers that START their watch each hour (there is 24 hours, that's why 24 zeros and 24 times 150), and calls the Fitness
function with said vector.
The Fitness function first converts real numbers to integers (R as.integer
function just strips off any number after decimal point, no rounding), and assigns the soldier to its 6 hours of work. It does that by adding the number of soldiers that start at x[i]
to y[i, i+1, ... i+7]
without those two hours when soldiers are resting.
Because the soldiers guard around the clock, those last 7 hours in the y
are added to the first 7 hours of y
and then only first 24 values of y
are considered.
Then we compare the generated vector of soldiers on the watch to the required one, and if there are any FALSE
s in the vector, Fitness
returns a very big negative number (GA always takes bigger number as a better one).
In the end we want to 'hire' as little soldiers as possible, that's why we negate the result (lower number of soldiers required = higher negated number) so the GA finds the best result.
The rest is pretty self explanatory, we call the GA function, we fiddle with its settings and display the result.