Genetic algorithm - shift planning - artificial-intelligence

I have some basic genetic algorithm knowledge, I've programmed a simple application finding X maximizing value of some function, but what I'm struggling with now is how should chromosome, individual, population etc. look like for some more complex problems like shift planning. Let's say we have some employees, some shifts and we want to assign them to each other. How shall the key parts of genetic algorithm look like to make it work for such data?

Let me make a few assumptions to showcase an example of how you can make a genetic algorithm model for this problem.
Assumptions
Let there be n employees labelled e_1, e_2, ..., e_n and n shifts labelled s_1, s_2, ..., s_n
Let n be an even number for simplicity of explanation
Chromosome of an individual
Let each chromosome consist of n 2D tuples. Each tuple is a pair of a shift and an employee (s_i, e_i). n tuples is thus a mapping of all the employees to the shifts. Thus a chromosome will look something like this:
{ {s_x1, e_y1}, {s_x2, e_y2}, ... {s_xn, e_yn} }
where, xi, yi c {1,2, ..,n} for all i,
s_xi != s_xj for i != j,
e_yi != e_yj for i != j
Population
Depending on n we can have a population of D individuals each with the above chromosome configuration. You can start by randomizing the chromosome configurations for the D organisms at the start (although there can be better ways to do this).
Reproduction
Given a generation of D individuals pick any two individuals, say d_i and d_j, for crossover. Let us obtain 2 children in the next generation, say c_i and c_j. It should look like this (considering n as 4 for simplicity):
d_i = { {s_i1, e_i1}, {s_i2, e_i2}, s_i3, e_i3, {s_i4, e_i4} }
d_j = { {s_j1, e_j1}, {s_j2, e_j2}, s_j3, e_j3, {s_j4, e_j4} }
crosses over to reproduce,
c_i = { {s_i1, e_j3}, {s_i2, e_j2}, s_i3, e_j1, {s_i4, e_j4} }
c_j = { {s_j1, e_i3}, {s_j2, e_i2}, s_j3, e_i1, {s_j4, e_i4} }
How you do this computationally for larger n is what I will let you think.
I also have some ideas on how one can apply mutation to the model, but I will let you think that through as well (moreover this is just an example model to get you started).
Thoughts on a fitness function
Lets consider you have a cost fitness function called employee satisfaction which is a summation of happiness (say an integer between -10 and 10) of all employees within an individual of a population.
Now, say an employee (e_1) if given a certain shift (s_1), his happiness is -4, but if given another shift (s_4), his happiness is 10.
Then, the fitness (employee satisfaction) of an individual in the population can simply be (there can be more complicated mathematical functions for this) the sum of happiness of all n employees. The ideal best fitness scenario would be all employees have 10 happiness and employee satisfaction sums to n x 10 compared to the worst fitness (least employee satisfaction) being n x -10.

Related

Determine if two unsorted (short) arrays share the same elements?

this is a follow-up question to Determine if two unsorted arrays are identical?
Given two unsorted arrays A and B with the same number of distinct elements (positive integers>0), determine if A and B can be rearranged so that they are identical.
I don't want to actually rearrange the elements, just perform a quick and inexpensive check if it is possible (I need to perform this on a large number of such arrays).
I was thinking about a check based on the sum and product of the elements. I.e., if 1. and 2. are true, A and B can be rearranged so that they are identical:
a_1+a_2+...+a_n = b_1+b_2+...+b_n
a_1*a_2*...*a_n = b_1*b_2*...*b_n
However, the mathematical foundations of this approach seem shaky to me. Are there similar proofs, which are mathematically more rigorous?
By The Vieta formulas, the sum and the product of n numbers are the second and last coefficients of a polynomial having those numbers for roots (to a change of sign). The other coefficients remain free, leaving many possibilities for distinct numbers.
E.g. sum = 3, product = 4.
The polynomial x³-3x²-21x-4 has the roots -3.19, -0.19634, 6.3863.
The polynomial x³-3x²-12x-4 has the roots -2, -0.37228, 5.3723.
These two distinct triples have the desired properties.
Addendum:
Comparing all coefficients of the expansion of (x-a)(x-b)...(x-z), which are known as the elementary symmetric polynomials (a+b+...z, ab+bc+...za, abc+bcd+...zab, ..., ab..z) is enough to prove equality of the roots, whatever the order. But I would not recommend this very costly method.

Randomize matrix elements between two values while keeping row and column sums fixed (MATLAB)

I have a bit of a technical issue, but I feel like it should be possible with MATLAB's powerful toolset.
What I have is a random n by n matrix of 0's and w's, say generated with
A=w*(rand(n,n)<p);
A typical value of w would be 3000, but that should not matter too much.
Now, this matrix has two important quantities, the vectors
c = sum(A,1);
r = sum(A,2)';
These are two row vectors, the first denotes the sum of each column and the second the sum of each row.
What I want to do next is randomize each value of w, for example between 0.5 and 2. This I would do as
rand_M = (0.5-2).*rand(n,n) + 0.5
A_rand = rand_M.*A;
However, I don't want to just pick these random numbers: I want them to be such that for every column and row, the sums are still equal to the elements of c and r. So to clean up the notation a bit, say we define
A_rand_c = sum(A_rand,1);
A_rand_r = sum(A_rand,2)';
I want that for all j = 1:n, A_rand_c(j) = c(j) and A_rand_r(j) = r(j).
What I'm looking for is a way to redraw the elements of rand_M in a sort of algorithmic fashion I suppose, so that these demands are finally satisfied.
Now of course, unless I have infinite amounts of time this might not really happen. I therefore accept these quantities to fall into a specific range: A_rand_c(j) has to be an element of [(1-e)*c(j),(1+e)*c(j)] and A_rand_r(j) of [(1-e)*r(j),(1+e)*r(j)]. This e I define beforehand, say like 0.001 or something.
Would anyone be able to help me in the process of finding a way to do this? I've tried an approach where I just randomly repick the numbers, but this really isn't getting me anywhere. It does not have to be crazy efficient either, I just need it to work in finite time for networks of size, say, n = 50.
To be clear, the final output is the matrix A_rand that satisfies these constraints.
Edit:
Alright, so after thinking a bit I suppose it might be doable with some while statement, that goes through every element of the matrix. The difficult part is that there are four possibilities: if you are in a specific element A_rand(i,j), it could be that A_rand_c(j) and A_rand_r(i) are both too small, both too large, or opposite. The first two cases are good, because then you can just redraw the random number until it is smaller than the current value and improve the situation. But the other two cases are problematic, as you will improve one situation but not the other. I guess it would have to look at which criteria is less satisfied, so that it tries to fix the one that is worse. But this is not trivial I would say..
You can take advantage of the fact that rows/columns with a single non-zero entry in A automatically give you results for that same entry in A_rand. If A(2,5) = w and it is the only non-zero entry in its column, then A_rand(2,5) = w as well. What else could it be?
You can alternate between finding these single-entry rows/cols, and assigning random numbers to entries where the value doesn't matter.
Here's a skeleton for the process:
A_rand=zeros(size(A)) is the matrix you are going to fill
entries_left = A>0 is a binary matrix showing which entries in A_rand you still need to fill
col_totals=sum(A,1) is the amount you still need to add in every column of A_rand
row_totals=sum(A,2) is the amount you still need to add in every row of A_rand
while sum( entries_left(:) ) > 0
% STEP 1:
% function to fill entries in A_rand if entries_left has rows/cols with one nonzero entry
% you will need to keep looping over this function until nothing changes
% update() A_rand, entries_left, row_totals, col_totals every time you loop
% STEP 2:
% let (i,j) be the indeces of the next non-zero entry in entries_left
% assign a random number to A_rand(i,j) <= col_totals(j) and <= row_totals(i)
% update() A_rand, entries_left, row_totals, col_totals
end
update()
A_rand(i,j) = random_value;
entries_left(i,j) = 0;
col_totals(j) = col_totals(j) - random_value;
row_totals(i) = row_totals(i) - random_value;
end
Picking the range for random_value might be a little tricky. The best I can think of is to draw it from a relatively narrow distribution centered around N*w*p where p is the probability of an entry in A being nonzero (this would be the average value of row/column totals).
This doesn't scale well to large matrices as it will grow with n^2 complexity. I tested it for a 200 by 200 matrix and it worked in about 20 seconds.

Compact storage coefficients of a multivariate polynomial

The setup
I am writing a code for dealing with polynomials of degree n over d-dimensional variable x and ran into a problem that others have likely faced in the past. Such polynomial can be characterized by coefficients c(alpha) corresponding to x^alpha, where alpha is a length d multi-index specifying the powers the d variables must be raised to.
The dimension and order are completely general, but known at compile time, and could be easily as high as n = 30 and d = 10, though probably not at the same time. The coefficients are dense, in the sense that most coefficients are non-zero.
The number of coefficients required to specify such a polynomial is n + d choose n, which in high dimensions is much less than n^d coefficients that could fill a cube of side length n. As a result, in my situation I have to store the coefficients rather compactly. This is at a price, because retrieving a coefficient for a given multi-index alpha requires knowing its location.
The question
Is there a (straightforward) function mapping a d-dimensional multi-index alpha to a position in an array of length (n + d) choose n?
Ordering combinations
A well-known way to order combinations can be found on this wikipedia page. Very briefly you order the combinations lexically so you can easily count the number of lower combinations. An explanation can be found in the sections Ordering combinations and Place of a combination in the ordering.
Precomputing the binomial coefficients will speed up the index calculation.
Associating monomials with combinations
If we can now associate each monomial with a combination we can effectively order them with the method above. Since each coefficient corresponds with such a monomial this would provide the answer you're looking for. Luckily if
alpha = (a[1], a[2], ..., a[d])
then the combination you're looking for is
combination = (a[1] + 0, a[1] + a[2] + 1, ..., a[1] + a[2] + ... + a[d] + d - 1)
The index can then readily be calculated with the formula from the wikipedia page.
A better, more object oriented solution, would be to create Monomial and Polynomial classes. The Polynomial class would encapsulate a collection of Monomials. That way you can easily model a pathological case like
y(x) = 1.0 + x^50
using just two terms rather than 51.
Another solution would be a map/dictionary where the key was the exponent and the value is the coefficient. That would only require two entries for my pathological case. You're in business if you have a C/C++ hash map.
Personally, I don't think doing it the naive way with arrays is so terrible, even with a polynomial containing 1000 terms. RAM is cheap; that array won't make or break you.

efficient methods to do summation

Is there any efficient techniques to do the following summation ?
Given a finite set A containing n integers A={X1,X2,…,Xn}, where Xi is an integer. Now there are n subsets of A, denoted by A1, A2, ... , An. We want to calculate the summation for each subset. Are there some efficient techniques ?
(Note that n is typically larger than the average size of all the subsets of A.)
For example, if A={1,2,3,4,5,6,7,9}, A1={1,3,4,5} , A2={2,3,4} , A3= ... . A naive way of computing the summation for A1 and A2 needs 5 Flops for additions:
Sum(A1)=1+3+4+5=13
Sum(A2)=2+3+4=9
...
Now, if computing 3+4 first, and then recording its result 7, we only need 3 Flops for addtions:
Sum(A1)=1+7+5=13
Sum(A2)=2+7=9
...
What about the generalized case ? Is there any efficient methods to speed up the calculation? Thanks!
For some choices of subsets there are ways to speed up the computation, if you don't mind doing some (potentially expensive) precomputation, but not for all. For instance, suppose your subsets are {1,2}, {2,3}, {3,4}, {4,5}, ..., {n-1,n}, {n,1}; then the naive approach uses one arithmetic operation per subset, and you obviously can't do better than that. On the other hand, if your subsets are {1}, {1,2}, {1,2,3}, {1,2,3,4}, ..., {1,2,...,n} then you can get by with n-1 arithmetic ops, whereas the naive approach is much worse.
Here's one way to do the precomputation. It will not always find optimal results. For each pair of subsets, define the transition cost to be min(size of symmetric difference, size of Y - 1). (The symmetric difference of X and Y is the set of things that are in X or Y but not both.) So the transition cost is the number of arithmetic operations you need to do to compute the sum of Y's elements, given the sum of X's. Add the empty set to your list of subsets, and compute a minimum-cost directed spanning tree using Edmonds' algorithm (http://en.wikipedia.org/wiki/Edmonds%27_algorithm) or one of the faster but more complicated variations on that theme. Now make sure that when your spanning tree has an edge X -> Y you compute X before Y. (This is a "topological sort" and can be done efficiently.)
This will give distinctly suboptimal results when, e.g., you have {1,2}, {3,4}, {1,2,3,4}, {5,6}, {7,8}, {5,6,7,8}. After deciding your order of operations using the procedure above you could then do an optimization pass where you find cheaper ways to evaluate each set's sum given the sums already computed, and this will probably give fairly decent results in practice.
I suspect, but have made no attempt to prove, that finding an optimal procedure for a given set of subsets is NP-hard or worse. (It is certainly computable; the set of possible computations you might do is finite. But, on the face of it, it may be awfully expensive; potentially you might be keeping track of about 2^n partial sums, be adding any one of them to any other at each step, and have up to about n^2 steps, for a super-naive cost of (2^2n)^(n^2) = 2^(2n^3) operations to try every possibility.)
Assuming that 'addition' isn't simply an ADD operation but instead some very intensive function involving two integer operands, then an obvious approach would be to cache the results.
You could achieve that via a suitable data structure, for example a key-value dictionary containing keys formed by the two operands and the answers as the value.
But as you specified C in the question, then the simplest approach would be an n by n array of integers, where the solution to x + y is stored at array[x][y].
You can then repeatedly iterate over the subsets, and for each pair of operands you check the appropriate position in the array. If no value is present then it must be calculated and placed in the array. The value then replaces the two operands in the subset and you iterate.
If the operation is commutative then the operands should be sorted prior to looking up the array (i.e. so that the first index is always the smallest of the two operands) as this will maximise "cache" hits.
A common optimization technique is to pre-compute intermediate results. In your case, you might pre-compute all sums with 2 summands from A and store them in a lookup table. This will result in |A|*|A+1|/2 table entries, where |A| is the cardinality of A.
In order to compute the element sum of Ai, you:
look up the sum of the first two elements of Ai and save them in tmp
while there is an element x left in Ai:
look up the sum of tmp and x
In order to compute the element sum of A1 = {1,3,4,5} from your example, you do the following:
lookup(1,3) = 4
lookup(4,4) = 8
lookup(8,5) = 13
Note that computing the sum of any given Ai doesn't require summation, since all the work has already been conducted while pre-computing the lookup table.
If you store the lookup table in a hash table, then lookup() is in O(1).
Possible optimizations to this approach:
construct the lookup table while computing the summation results; hence, you only compute those summations that you actually need. Your lookup table is now a cache.
if your addition operation is commutative, you can save half of your cache size by storing only those summations where the smaller summand comes first. Then modify lookup() such that lookup(a,b) = lookup(b,a) if a > b.
If assuming summation is time consuming action you can find LCS of every pair of subsets (by assuming they are sorted as mentioned in comments, or if they are not sorted sort them), after that calculate sum of LCS of maximum length (over all LCS in pairs), then replace it's value in related arrays with related numbers, update their LCS and continue this way till there is no LCS with more than one number. Sure this is not optimum, but it's better than naive algorithm (smaller number of summation). However you can do backtracking to find best solution.
e.g For your sample input:
A1={1,3,4,5} , A2={2,3,4}
LCS (A_1,A_2) = {3,4} ==>7 ==>replace it:
A1={1,5,7}, A2={2,7} ==> LCS = {7}, maximum LCS length is `1`, so calculate sums.
Still you can improve it by calculation sum of two random numbers, then again taking LCS, ...
NO. There is no efficient techique.
Because it is NP complete problem. and there are no efficient solutions for such problem
why is it NP-complete?
We could use algorithm for this problem to solve set cover problem, just by putting extra set in set, conatining all elements.
Example:
We have sets of elements
A1={1,2}, A2={2,3}, A3 = {3,4}
We want to solve set cover problem.
we add to this set, set of numbers containing all elements
A4 = {1,2,3,4}
We use algorhitm that John Smith is aking for and we check solution A4 is represented whit.
We solved NP-Complete problem.

Genetic Algorithm roulette wheel selection

I am having issues understanding the algorithm. Here is the most popular one seen online
for all members of population
sum += fitness of this individual
end for
for all members of population
probability = sum of probabilities + (fitness / sum)
sum of probabilities += probability
end for
loop until new population is full
do this twice
number = Random between 0 and 1
for all members of population
if number > probability but less than next probability
then you have been selected
end for
end
create offspring
end loop
for all members of population
probability = sum of probabilities + (fitness / sum)
sum of probabilities += probability
end for
^^^this piece in particular confuses me. What are the "sum of probabilities" and even "probability" in the context of an individual in a population? Are these like values individuals have on inception?
That is a very obfuscated piece of code.
In that second block of code, probability is a variable attached to each member of the population, and sum of probabilities is a global variable for the whole population.
Now, what the roulette wheel metaphor is saying, is that the entire population can be represented as a roulette wheel, and each member of the population has a slice in that roulette wheel proportional to its relative fitness. That code is doing the dirty work behind that metaphor-- instead of wedges on a wheel, the members are now represented by proportional intervals on the line segment [0,1], which is a customary way to represent probabilities.
To do that, you technically need two numbers, a start and an end, for each member. But the first member's start is going to be 0; the second member's start is going to be the end of the first member; etc, until the last member, which has an end of 1.
That's what that code is doing. Sum of probabilities starts out at 0, and the first time through the loop, the probability is what you intuitively thought it would be. It is marking the end point of the first member. Then the "sum of probabilities" is updated. The second time through the loop, the "probability" is what you intuitively thought it would be... shifted over by the "sum of probabilities." And so it goes.
So the first loop is summing fitness values as a prelude to normalizing things. The second loop, that you ask about, is normalizing and arranging those normalized probabilities in the unit interval. And the third (most complex) loop is picking two random numbers, matching them up with two members of the population, and mating them. (Note that the assumption is that those members are in some array-like format so that you can sequentially check their endpoints against the random number you've rolled.)
The key is in
probability = sum of probabilities + (fitness / sum)
and
if number > probability but less than next probability
then you have been selected
Probability is a measurement of the individual's chance to create offspring; the size of it's slice on the roulette wheel. The sum of probabilities is the total size of the roulette wheel.
Each individual's probability is a function of it's fitness.
I found this link helpful while trying to understand the algorithm.

Resources