CPLE How to set a decision variable array dynamically - algorithm

I want to formulate a flexible job shop scheduling problem with MIP instead of CP.
If there is an array indicating number of operations of each job.
num_op = [3, 2, 5]
And Xijk is the decision variable indicating if the j-th operation of job i is processed on machine k or not.
My question is that I don't know how t initiate the 3-D array with different number of operations of each job.
I wrote this dvar boolean x[i in Jobs][j in][k in Machs];, and I don't know to how to complete it.
Please help me. Thanks!!

If I understand your example correctly then your definition of num_op indicates that you have three different jobs, the first job has 3 operations, the second has 2 and the last job has 5 operations. That would mean that the second dimension of Xijk has to change depending on the first dimension. Such a flexible array size is not possible with CPLEX.
Here is an alternative:
Define M to be the maximum number of operations (5 in your case).
Define dvar boolean x[i in Jobs][j in 1..M][k in Machs];
Explicitly fix all variables to 0 that correspond to non-existing operations:
forall (i in Jobs, j in 1..M, k in Machs) if (j > num_op[i]) X[i][j][k] == 0;
The last step is even optional: You can define the variables for non-existing operations but just not use them anywhere in your model (this may give a warning for unused variables, though).
Another option is to create a tuple tuple { int i; int j; int k }, then create a tuple set that contains all the valid combinations of i, j, k and index X by this tuple set.

Related

Incorrect Recursive approach to finding combinations of coins to produce given change

I was recently doing a project euler problem (namely #31) which was basically finding out how many ways we can sum to 200 using elements of the set {1,2,5,10,20,50,100,200}.
The idea that I used was this: the number of ways to sum to N is equal to
(the number of ways to sum N-k) * (number of ways to sum k), summed over all possible values of k.
I realized that this approach is WRONG, namely due to the fact that it creates several several duplicate counts. I have tried to adjust the formula to avoid duplicates, but to no avail. I am seeking the wisdom of stack overflowers regarding:
whether my recursive approach is concerned with the correct subproblem to solve
If there exists one, what would be an effective way to eliminate duplicates
how should we approach recursive problems such that we are concerned with the correct subproblem? what are some indicators that we've chosen a correct (or incorrect) subproblem?
When trying to avoid duplicate permutations, a straightforward strategy that works in most cases is to only create rising or falling sequences.
In your example, if you pick a value and then recurse with the whole set, you will get duplicate sequences like 50,50,100 and 50,100,50 and 100,50,50. However, if you recurse with the rule that the next value should be equal to or smaller than the currently selected value, out of those three you will only get the sequence 100,50,50.
So an algorithm that counts only unique combinations would be e.g.:
function uniqueCombinations(set, target, previous) {
for all values in set not greater than previous {
if value equals target {
increment count
}
if value is smaller than target {
uniqueCombinations(set, target - value, value)
}
}
}
uniqueCombinations([1,2,5,10,20,50,100,200], 200, 200)
Alternatively, you can create a copy of the set before every recursion, and remove the elements from it that you don't want repeated.
The rising/falling sequence method also works with iterations. Let's say you want to find all unique combinations of three letters. This algorithm will print results like a,c,e, but not a,e,c or e,a,c:
for letter1 is 'a' to 'x' {
for letter2 is first letter after letter1 to 'y' {
for letter3 is first letter after letter2 to 'z' {
print [letter1,letter2,letter3]
}
}
}
m69 gives a nice strategy that often works, but I think it's worthwhile to better understand why it works. When trying to count items (of any kind), the general principle is:
Think of a rule that classifies any given item into exactly one of several non-overlapping categories. That is, come up with a list of concrete categories A, B, ..., Z that will make the following sentence true: An item is either in category A, or in category B, or ..., or in category Z.
Once you have done this, you can safely count the number of items in each category and add these counts together, comfortable in the knowledge that (a) any item that is counted in one category is not counted again in any other category, and (b) any item that you want to count is in some category (i.e., none are missed).
How could we form categories for your specific problem here? One way to do it is to notice that every item (i.e., every multiset of coin values that sums to the desired total N) either contains the 50-coin exactly zero times, or it contains it exactly once, or it contains it exactly twice, or ..., or it contains it exactly RoundDown(N / 50) times. These categories don't overlap: if a solution uses exactly 5 50-coins, it pretty clearly can't also use exactly 7 50-coins, for example. Also, every solution is clearly in some category (notice that we include a category for the case in which no 50-coins are used). So if we had a way to count, for any given k, the number of solutions that use coins from the set {1,2,5,10,20,50,100,200} to produce a sum of N and use exactly k 50-coins, then we could sum over all k from 0 to N/50 and get an accurate count.
How to do this efficiently? This is where the recursion comes in. The number of solutions that use coins from the set {1,2,5,10,20,50,100,200} to produce a sum of N and use exactly k 50-coins is equal to the number of solutions that sum to N-50k and do not use any 50-coins, i.e. use coins only from the set {1,2,5,10,20,100,200}. This of course works for any particular coin denomination that we could have chosen, so these subproblems have the same shape as the original problem: we can solve each one by simply choosing another coin arbitrarily (e.g. the 10-coin), forming a new set of categories based on this new coin, counting the number of items in each category and summing them up. The subproblems become smaller until we reach some simple base case that we process directly (e.g. no allowed coins left: then there is 1 item if N=0, and 0 items otherwise).
I started with the 50-coin (instead of, say, the largest or the smallest coin) to emphasise that the particular choice used to form the set of non-overlapping categories doesn't matter for the correctness of the algorithm. But in practice, passing explicit representations of sets of coins around is unnecessarily expensive. Since we don't actually care about the particular sequence of coins to use for forming categories, we're free to choose a more efficient representation. Here (and in many problems), it's convenient to represent the set of allowed coins implicitly as simply a single integer, maxCoin, which we interpret to mean that the first maxCoin coins in the original ordered list of coins are the allowed ones. This limits the possible sets we can represent, but here that's OK: If we always choose the last allowed coin to form categories on, we can communicate the new, more-restricted "set" of allowed coins to subproblems very succinctly by simply passing the argument maxCoin-1 to it. This is the essence of m69's answer.
There's some good guidance here. Another way to think about this is as a dynamic program. For this, we must pose the problem as a simple decision among options that leaves us with a smaller version of the same problem. It boils out to a certain kind of recursive expression.
Put the coin values c0, c1, ... c_(n-1) in any order you like. Then define W(i,v) as the number of ways you can make change for value v using coins ci, c_(i+1), ... c_(n-1). The answer we want is W(0,200). All that's left is to define W:
W(i,v) = sum_[k = 0..floor(200/ci)] W(i+1, v-ci*k)
In words: the number of ways we can make change with coins ci onward is to sum up all the ways we can make change after a decision to use some feasible number k of coins ci, removing that much value from the problem.
Of course we need base cases for the recursion. This happens when i=n-1: the last coin value. At this point there's a way to make change if and only if the value we need is an exact multiple of c_(n-1).
W(n-1,v) = 1 if v % c_(n-1) == 0 and 0 otherwise.
We generally don't want to implement this as a simple recursive function. The same argument values occur repeatedly, which leads to an exponential (in n and v) amount of wasted computation. There are simple ways to avoid this. Tabular evaluation and memoization are two.
Another point is that it is more efficient to have the values in descending order. By taking big chunks of value early, the total number of recursive evaluations is minimized. Additionally, since c_(n-1) is now 1, the base case is just W(n-1)=1. Now it becomes fairly obvious that we can add a second base case as an optimization: W(n-2,v) = floor(v/c_(n-2)). That's how many times the for loop will sum W(n-1,1) = 1!
But this is gilding a lilly. The problem is so small that exponential behavior doesn't signify. Here is a little implementation to show that order really doesn't matter:
#include <stdio.h>
#define n 8
int cv[][n] = {
{200,100,50,20,10,5,2,1},
{1,2,5,10,20,50,100,200},
{1,10,100,2,20,200,5,50},
};
int *c;
int w(int i, int v) {
if (i == n - 1) return v % c[n - 1] == 0;
int sum = 0;
for (int k = 0; k <= v / c[i]; ++k)
sum += w(i + 1, v - c[i] * k);
return sum;
}
int main(int argc, char *argv[]) {
unsigned p;
if (argc != 2 || sscanf(argv[1], "%d", &p) != 1 || p > 2) p = 0;
c = cv[p];
printf("Ways(%u) = %d\n", p, w(0, 200));
return 0;
}
Drumroll, please...
$ ./foo 0
Ways(0) = 73682
$ ./foo 1
Ways(1) = 73682
$ ./foo 2
Ways(2) = 73682

How to get the minimal absolute value of the differences?

Given an array a[], and do the operation a[i]-x, a[j]+x (x <= a[i]) to two elements of this array for each time. After at most K times operation like that, to ensure the value of max(abs (a[i] - a[j])) is smallest, and get this smallest value?
My solution:
Each time, choose two number from this array, and ensure their sum is constant. After K times operation,
we can get the minimal absolute value of the difference of two elements in the array.
However, I do not know whether my idea is correct? if not, how to solve it correctly?
If I correctly understand your algorithm/question there is no need to make any calculations during performing a[i]-x, a[j]+x operations. So my suggestion is:
1) make required number of a[i]-x, a[j]+x operations
2) do the following procedure (in pseudo-code):
_aSorted[] = sort(_a[])
_dif = max integer value
for (i=0; i < _a[].length - 1; i++){
if(abs(_aSorted[i]-_aSorted[i+1]) < _dif)
_dif = abs(_aSorted[i] -_aSorted[i+1]);
}
So after this procedure _dif holds the required result

How to generate a random integer in a range

a program I'm writing requires me to simulate the mutation of genes. If a certain instance (J) of the gene is selected for mutation, it must randomly become one of a predefined subset of alternative genes. These discrete genes are marked by the integers in the range 0 to K-1, where K equals the total number of alleles.
So basically, I need help writing the code to randomly select an integer in the range 0 to K-1 that does not equal J. Any help is greatly appreciated!
ANOTHER EDIT: Thanks for all the help so far, I've come up with the following, which ignores the requirement that i cannot equal J. However, a further problem I've encountered is that the process must be repeated multiple times, and due to the same seed being used each time the value of i is always the same. How should I go about ensuring the seed value doesn't remain the same throughout every generation? Again, any help is greatly appreciated!
program randtest
implicit none
real*4 :: u(5)
integer :: i(5)
integer :: k = 4
integer, dimension (1) :: seed = (/2817/)
call random_seed(put=seed)
call random_number(u)
i = floor((k+1)*u)
print *, i
end program randtest
One can indeed use the method given in the answers to the other question, for the set {0, 1, ..., K-1}. The complication that J (0<=J<=K-1) can be handled by rejecting J when it is sampled.
However, a better approach is to note that there are K-2 valid integers: {0, 1, ..., J-1, J+1, ..., K-1}. So, use the method to generate an integer over {0, 1, ..., K-2} and just shift up anything that would be affected by rejecting J.
call random_number(u)
i = FLOOR((K-1)*u) !this would be how I would define the range
if (i.ge.J) i=i+1

Finding pairs that sum to a multiple of k

Suppose, I have a set of N(N<=10^10) natural numbers. Out of these, I want to form sets of 2 numbers such that their sum is divisible by k. Suppose, that N=4,ie, Numbers: 1, 2, 3, 4 and k=2. Hence, the formed sets would be:: (1,3) and (2,4).
No repetitions and the first element of the set should be less than the second element.
Following is my code and logic. But I don't know why it is giving incorrect answers for lage values of N.:
int c[] = new int[K];
for (long j=1;j<=N;j++) {
++c[(int)j%K];//storing remainder in array
}
long count = 0;
if (K%2==0)
count = (c[0]*(c[0]-1) + c[K/2]*(c[K/2]-1))/2;//modulus that have value 0 or half of k, should be paired together, in C(N,2) ways.
else
count = c[0]*(c[0]-1)/2;
for (int j=1;j<(K+1)/2;j++) {
count+=c[j]*c[K-j];//sets whose modulus form a sum of K
}
I see at least two things:
First, in this line:
++c[(int)j%K];//storing remainder in array
I'm pretty sure it'll do the cast to int before actually doing the % operation (but not 100% sure).
Second, in the rest of the code, for all of the count = ... lines, you are doing arithmetic on ints then assigning the result to a long. The implicit cast to long is not done until after the arithmetic operations are done. Thus, if the operations overflow an int, you end up overflowing then casting to a long.
If you want to fix that, you'll have to explicitly do casts to long on the right-hand side to make sure that none of the arithmetic operations operate on two ints. (Though unless you have memory constraints, it'll be better to just use longs everywhere instead of ints, with the exception of j and K)

Finding sets that are a subset of a specific set

Lets say I have 4 different values A,B,C,D with sets of identifiers attached.
A={1,2,3,4,5}
B={8,9,4}
C={3,4,5}
D={12,8}
And given set S of identifiers {1,30,3,4,5,12,8} I want it to return C and D. i.e. retrieve all sets from a group of sets for which S is a superset.
Is there any algorithms to perform this task efficiently (Preferably with low memory complexity. Using external device for storing data is not an option) ?
A trivial solution would be for each member in the superset S retrieve list of sets that include that member (basically inverted index) and for each returned set check that all of his members are in the superset. Unfortunately because on average the superset will include at least one member for each set there is a significant and unacceptable performance hit with this approach.
I am trying to do this in Java. Set consist of integers and the value they identify is an object.
Collection of sets is not static and bound to change during the course of execution. There will be some limit on the set number though.
Set size is not limited. But on average it's between 1 and 20.
Go through each element x in S.
For each set t for which x ∈ t, increment a counter—call it tcount—associated with t.
After all that, for each set t for which tcount = | t |, you know that t ⊆ S.
Application.
After step 2.
Acount = 4,
Bcount = 1,
Ccount = 3,
Dcount = 2.
Step 3 processing.
Acount ≠ |A| (4 ≠ 5) — Reject,
Bcount ≠ |B| (1 ≠ 3) — Reject,
Ccount = |C| (3 = 3) — Accept,
Dcount = |D| (2 = 2) — Accept.
Note after cgkanchi note: The following algorithm is under the assumption that you don't really use sets but arrays. If that is not the case, you should look for a method which implements intersection of sets and then the problem is trivial. This is about how to implement the notion of intersection using arrays.
Sort all sets using heapsort for in-place sorting O(1) space. It runs in O(nlogn) and soon enough it will pay you back.
For each set L of all sets:
2.1. j = 0
2.2. For the i element in L:
2.2.1. Starting from j element find L[i] in S for which L[i] = S[j] else reject. If L and S and large enough use binary search or interpolation search (for the second one, have a look at your data distibution)
2.3. Accept
As for Java, I’d use a Hashtable for the lookup table of the elements in S. Then for each element in X, the set you want to test if it’s a subset of S, test if it’s in the lookup table. If all elements of X are also in S, then S is a superset of X.

Resources