How to determine which items are on the critical path in GAMS? - linear-programming

This is my current code on GAMS. Yes, I know it can be more concise, but bear with me here:
set activity /a*q/;
parameter duration (activity) "in days"
/a 15, b 4, c 5, d 10, e 4, f 15, g 15, h 5, i 5, j 10, k 4, l 3, m 4, n 20, o 5,
p 2, q 2/;
alias (activity, x, y);
set prec(x,y) "Precedence Order"
/A.(B,C,D)
(B,C,D).E
E.(F,G,H)
F.N
G.(K,I)
H.I
K.M
I.J
J.L
L.M
M.N
N.O
O.P
P.Q/ ;
Free Variable
T Completion Time;
Nonnegative Variables
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q;
equations
t_A, t_B, t_C, t_D, t_E, t_F, t_G, t_H, t_I, t_J, t_K, t_L, t_M, t_N, t_O, t_P,
t_Q, s_AB, s_AC, s_AD, s_BE, s_CE, s_DE, s_EF, s_EG, s_EH, s_FN, s_GK, s_GI,
s_HI, s_KM, s_IJ, s_JL, s_LM, s_MN, s_NO, s_OP, s_PQ;
t_A.. T =G= A + 15;
t_B.. T =G= B + 4;
t_C.. T =G= C + 5;
t_D.. T =G= D + 10;
t_E.. T =G= E + 4;
t_F.. T =G= F + 15;
t_G.. T =G= G + 15;
t_H.. T =G= H + 5;
t_I.. T =G= I + 5;
t_J.. T =G= J + 10;
t_K.. T =G= K + 4;
t_L.. T =G= L + 3;
t_M.. T =G= M + 4;
t_N.. T =G= N + 20;
t_O.. T =G= O + 5;
t_P.. T =G= P + 2;
t_Q.. T =G= Q + 10;
s_AB.. A + 15 =L= B;
s_AC.. A + 15 =L= C;
s_AD.. A + 15 =L= D;
s_BE.. B + 4 =L= E;
s_CE.. C + 5 =L= E;
s_DE.. D + 10 =L= E;
s_EF.. E + 4 =L= F;
s_EG.. E + 4 =L= G;
s_EH.. E + 4 =L= H;
s_FN.. F + 15 =L= N;
s_GK.. G + 15 =L= K;
s_GI.. G + 15 =L= I;
s_HI.. H + 5 =L= I;
s_KM.. K + 4 =L= M;
s_IJ.. I + 5 =L= J;
s_JL.. J + 10 =L= L;
s_LM.. L + 3 =L= M;
s_MN.. M + 4 =L= N;
s_NO.. N + 20 =L= O;
s_OP.. O + 5 =L= P;
s_PQ.. P + 2 =L= Q;
model thesis /all/;
solve thesis using lp minimizing t;
display t.l;
This code gives me a ton of details, such as what days I should start each activity. However, it doesn't tell me (as far as I can see), which activities are on the critical path. How can I determine this using GAMS?

A dependency lies on the critical path if the marginal on the dependency equation (s_AB etc. in your formulation) is -1. You can check this in the listing (.lst) file or by using the code below:
set activity /a*q/;
parameter duration (activity) "in days"
/a 15, b 4, c 5, d 10, e 4, f 15, g 15, h 5, i 5, j 10, k 4, l 3, m 4, n 20, o 5,
p 2, q 2/;
alias (activity, x, y);
set prec(x,y) "dependency Order"
/A.(B,C,D)
(B,C,D).E
E.(F,G,H)
F.N
G.(K,I)
H.I
K.M
I.J
J.L
L.M
M.N
N.O
O.P
P.Q/;
Free Variable
T Completion Time;
Nonnegative Variables
start(x);
equations
t_bound(x)
dependency(x,y);
t_bound(x).. T =G= start(x) + duration(x);
dependency(x,y)$prec(x,y).. start(x) + duration(x) =l= start(y);
model thesis /all/;
solve thesis using lp minimizing t;
set criticalpath(x,y);
criticalpath(x,y) = 1$(dependency.M(x,y) < 0);
display t.l, criticalpath;

Related

Problem with multiplication of matrices following Glynn's formula for calculating the permanent

I'm trying to implement in C++ the calculation of the matrix permanent following the Glynn formula.
I try to explain briefly how this formula works. Suppose we have an nxn matrix.
| a b c |
| d e f |
| g h i |
To calculate the permanent with the Glynn formula I should try to execute "a kind" of matrix product with a matrix that is a table of truths of length 2^n with n/2 rows and n columns.
Something like this. Suppose a matrix with n = 3.
| a b c | |+ + +|
| d e f | |+ - +|
| g h i | |+ + -|
|+ - -|
development of the formula. I have to get:
∆(a + b + c)(d + e + f)(g + h + i)
where:
∆ è equal to the product of the first of the sign matrix (therefore + * + * + = +). The positive sign of a, b and c I got it by multiplying the first column of the matrix of letters by the sign of the first row of the sign matrix.
The order is then: multiply the first column of matrix A for the first row of the matrix of signs, multiply the second column of matrix A for the first row of the matrix of signs and then multiply the last column of matrix A for the first line of the matrix of the signs.
This is the first step. The second will be to multiply the first column of matrix A for the second row of the matrix of signs, multiply the second column of matrix A for the second row of the matrix of signs and then multiply the third column of matrix A for the second row of matrix signs and so on..
The end result is this:
= + (a + b + c)(d + e + f)(g + h + i)
- (a - b + c)(d - e + f)(g - h + i)
- (a + b - c)(d + e - f)(g + h - i)
+ (a - b - c)(d - e - f)(g - h - i)
I am trying to implement this algorithm in C. I have correctly created a random matrix nxn and the matrix of the signs I have encoded it in this way to perform the multiplications in a simple way (+ = 1 and - = -1).
So the product I have to do is:
| a b c | |1 1 1|
| d e f | |1 -1 1|
| g h i | |1 1 -1|
|1 -1 -1|
The function that I tried to create to run those products and those sums is:
double permanent(double input_matrix[n][n], int sign_matrix[][n]){
int rows = pow (2, n) ;
int partial_result = 0;
int result = 1;
for(int r = 0; r < n; r++)
{
for(int c = 0; c < n; c++)
{
partial = partial + input_matrix[c][r] * sign_matrix[r][c];
//cout << parziale << endl;
}
cout << partial << endl;
partial_result = partial_result * parziale;
partial = 0;
}
The problem is that when I execute partial = partial + input_matrix [c][r] * sign_matrix [r][c]; I can not "hold the line of the matrix of signs steady, with the cause that the product is wrong because I multiply the first column of matrix A for the first row of the sign matrix (right). second row of the sign matrix (wrong! I should also multiply the second column for the first row of the sign matrix as in the written formula).
Any suggestions?
I think that you really need to check twice your understanding of the equation. Remember that each summation or multiplication is a for loop. So, by using the notation in the original paper, you get this:
#include <vector>
#include <cassert>
using mat = std::vector<std::vector<double>>;
double permanent(const mat& input_matrix, const mat& sign_matrix)
{
int m = input_matrix.size();
assert(m > 2);
assert(input_matrix[0].size() == m);
assert(sign_matrix.size() == m);
int cols = sign_matrix[0].size();
assert(cols == 1 << (m - 1));
double result = 0;
for (int t = 0; t < cols; ++t) {
double delta = 1;
for (int k = 0; k < m; ++k) {
delta *= sign_matrix[k][t];
}
double p = 1;
for (int j = 0; j < m; j++) {
double s = 0;
for (int i = 0; i < m; i++) {
s += sign_matrix[i][t] * input_matrix[i][j];
}
p *= s;
}
result += delta * p;
}
return result / cols;
}
int main()
{
mat A = {
{ 1, 4, 7, },
{ 2, 5, 8, },
{ 3, 6, 9, },
};
mat sign_mat = {
{ 1, 1, 1, 1, },
{ 1, -1, 1, -1, },
{ 1, 1, -1, -1, },
};
auto perA = permanent(A, sign_mat);
}

Smallest n-bit integer c that has k 1-bits and is the sum of two n-bit integers that have g, h bits set to 1(dynamic programming)

I am trying to solve the following problem:
Find the smallest n-bit integer c that has k 1-bits and is the sum of two n-bit integers that have g, h bits set to 1. g, h, k <= n
To start with, n-bit integer here means that we may use all n bits, i.e. max. value of such an integer is 2^n - 1. The described integer may not exist at all.
It is obvious the case k > g + h has no solutions and for g + h = k the answer is just 2^k - 1 (first k bits are 1-bits, k - n zeroes in the front).
As for some examples of what the program is supposed to do:
g = h = k = 4, n = 10 :
0000001111 + 0000001111 = 0000011110
15 + 15 = 30 (30 should be the output)
(4, 6, 5, 10):
0000011110 + 0000111111 = 0001011101
30 + 63 = 93
(30, 1, 1, 31):
1 + (2^30 - 1) = 2^30
As I think of it, this is a dynamic programming problem and I've chosen the following approach:
Let dp[g][h][k][n][c] be the described integer and c is an optional bit for carrying. I try to reconstruct possible sums depending on the lowest-order bits.
So, dp[g][h][k][n + 1][0] is the minimum of
(0, 0): dp[g][h][k][n][0]
(0, 0): 2^n + dp[g][h][k - 1][n][1]
(1, 0): 2^n + dp[g - 1][h][k - 1][n][0]
(0, 1): 2^n + dp[g][h - 1][k - 1][n][0]
Similarly, dp[g][h][k][n + 1][1] is the minimum of
(1, 1): dp[g - 1][h - 1][k][n][0]
(1, 1): dp[g - 1][h - 1][k - 1][n][1] + 2^n
(1, 0): dp[g - 1][h][k][n][1]
(0, 1): dp[g][h - 1][k][n][1]
The idea isn't that hard but I'm not really experienced with such things and my algorithm doesn't work even for simplest cases. I've chosen top-down approach. It's hard for me to consider all the corner cases. I do not really know if I've properly chosen base of recursion, etc. My algorithm doesn't even work for the most basic case for g = h = k = 1, n = 2(the answer is 01 + 01 = 10). There shouldn't be an answer for g = h = k = 1, n = 1 but the algorithm gives 1(which is basically why the former example outputs 1 instead of 2).
So, here goes my awful code(only very basic C++):
int solve(int g, int h, int k, int n, int c = 0) {
if (n <= 0) {
return 0;
}
if (dp[g][h][k][n][c]) {
return dp[g][h][k][n][c];
}
if (!c) {
if (g + h == k) {
return dp[g][h][k][n][c] = (1 << k) - 1;
}
int min, a1, a2, a3, a4;
min = a1 = a2 = a3 = a4 = std::numeric_limits<int>::max();
if (g + h > k && k <= n - 1) {
a1 = solve(g, h, k, n - 1, 0);
}
if (g + h >= k - 1 && k - 1 <= n - 1) {
a2 = (1 << (n - 1)) + solve(g, h, k - 1, n - 1, 1);
}
if (g - 1 + h >= k - 1 && k - 1 <= n - 1) {
a3 = (1 << (n - 1)) + solve(g - 1, h, k - 1, n - 1, 0);
}
if (g + h - 1 >= k - 1 && k - 1 <= n - 1) {
a4 = (1 << (n - 1)) + solve(g, h - 1, k - 1, n - 1, 0);
}
min = std::min({a1, a2, a3, a4});
return dp[g][h][k][n][c] = min;
} else {
int min, a1, a2, a3, a4;
min = a1 = a2 = a3 = a4 = std::numeric_limits<int>::max();
if (g - 2 + h >= k && k <= n - 1) {
a1 = solve(g - 1, h - 1, k, n - 1, 0);
}
if (g - 2 + h >= k - 1 && k - 1 <= n - 1) {
a2 = (1 << (n - 1)) + solve(g - 1, h - 1, k - 1, n - 1, 1);
}
if (g - 1 + h >= k && k <= n - 1) {
a3 = solve(g - 1, h, k, n - 1, 1);
}
if (g - 1 + h >= k && k <= n - 1) {
a4 = solve(g, h - 1, k, n - 1, 1);
}
min = std::min({a1, a2, a3, a4});
return dp[g][h][k][n][c] = min;
}
}
You can construct the smallest sum based on the bit counts g, h, and k, without doing any dynamic programming at all. Assuming that g ≥ h (switch them otherwise) these are the rules:
k ≤ h ≤ g
11111111 <- g ones
111100000111 <- h-k ones + g-k zeros + k ones
1000000000110 <- n must be at least h+g-k+1
h ≤ k ≤ g
1111111111 <- g ones
11111100 <- h ones + k-h zeros
1011111011 <- n must be at least g+1
h ≤ g ≤ k
1111111100000 <- g ones + k-g ones
1100000011111 <- g+h-k ones, k-h zeros, k-g ones
11011111111111 <- n must be at least k+1, or k if g+h=k
Example: all values of k for n=10, g=6 and h=4:
k=1 k=2 k=3 k=4
0000111111 0000111111 0000111111 0000111111
0111000001 0011000011 0001000111 0000001111
---------- ---------- ---------- ----------
1000000000 0100000010 0010000110 0001001110
k=4 k=5 k=6
0000111111 0000111111 0000111111
0000001111 0000011110 0000111100
---------- ---------- ----------
0001001110 0001011101 0001111011
k=6 k=7 k=8 k=9 k=10
0000111111 0001111110 0011111100 0111111000 1111110000
0000111100 0001110001 0011000011 0100000111 0000001111
---------- ---------- ---------- ---------- ----------
0001111011 0011101111 0110111111 1011111111 1111111111
Or, going straight to the value of c without calculating a and b first:
k ≤ h ≤ g
c = (1 << (g + h - k)) + ((1 << k) - 2)
h ≤ k ≤ g
c = (1 << g) + ((1 << k) - 1) - (1 << (k - h))
h ≤ g ≤ k
c = ((1 << (k + 1)) - 1) - (1 << ((g - h) + 2 * (k - g)))
h + g = k
c = (1 << k) - 1
which results in this disappointingly mundane code:
int smallest_sum(unsigned n, unsigned g, unsigned h, unsigned k) {
if (g < h) {unsigned swap = g; g = h; h = swap;}
if (k == 0) return (g > 0 || h > 0 || n < 1) ? -1 : 0;
if (h == 0) return (g != k || n < k) ? -1 : (1 << k) - 1;
if (k <= h) return (n <= h + g - k) ? -1 : (1 << (g + h - k)) + ((1 << k) - 2);
if (k <= g) return (n <= g) ? -1 : (1 << g) + ((1 << k) - 1) - (1 << (k - h));
if (k < g + h) return (n <= k) ? -1 : (1 << (k + 1)) - 1 - (1 << (2 * k - g - h));
if (k == g + h) return (n < k) ? -1 : (1 << k) - 1;
return -1;
}
Some example results:
n=31, g=15, h=25, k=10 -> 1,073,742,846 (1000000000000000000001111111110)
n=31, g=15, h=25, k=20 -> 34,602,975 (0000010000011111111111111011111)
n=31, g=15, h=25, k=30 -> 2,146,435,071 (1111111111011111111111111111111)
(I compared the results with those of a brute-force algorithm for every value of n, g, h and k from 0 to 20 to check correctness, and found no differences.)
I'm not too convinced about the dynamic programming approach. If I understand correctly, you would need to define how to go to dp[g + 1][h][k][n], dp[g][h + 1][k][n], dp[g][h][k + 1][n] and dp[g][h][k][n + 1], with and without the carry bit, in function of previous computations, and I'm not sure about what are the right rules for all of those.
I think an easier way to think of the problem is as an A* search tree, where each node contains two partial candidate numbers to add, let's call them G and H. You start with a node with G = 0 and H = 0 at level m = 0, and work as follows:
If G + H has n or fewer bits and k 1 bits, that's the solution, you found it!
Otherwise, if
n - m < number of 1 bits in G + H - k
discard the node (no solution possible).
Otherwise, if
(g + h) - (number of 1 bits in G + number of 1 bits in H) < k - number of 1 bits in G + H
discard the node (not viable candidates).
Otherwise, branch the node into a new level. Generally you make up to four children of each node, prefixing G and H with 0 and 0, 0 and 1, 1 and 0 or 1 and 1 respectively. However:
You can only precede G with a 1 if the number of 1 bits in G is fewer than g, and similarly for H and h.
At level m (G and H have m bits), you can only precede G with a 0 if
n - m > g - number of 1 bits in G
and similarly for H and h.
If G == H and g == h, you can skip one of 0 and 1 and 1 and 0, since they will lead to the same subtree.
Continue to the next node and repeat until you find a solution or you don't have any more nodes to visit.
The order in which you visit the nodes is important. You should store the nodes in a priority queue/heap such that the next node is always the first node that could potentially lead to the best solution. This is actually easy, you just need to take for each node G + H and prefix it with the necessary number of 1 bits to reach k; that's the best possible solution from there.
There are possibly better rules to discard invalid nodes (steps 2 and 3), but the idea of the algorithm is the same.

Lagrange's Four Square theorem under modulus

Given an integer n, print out all possible combinations of integer values of A,B,C and D which solve the equation A^2+B^2+C^2+D^2=N under modulus user given integer p
int sum(int n)
{
int a, b, c, d, na, nb, nc, nd;
int count = 0;
for (a = 0, na = n; a * a <= na; a++)
{
for (b = a, nb = na - a * a; b * b <= nb; b++)
{
for (c = b, nc = nb - b * b; c * c <= nc; c++) {
nd = nc - c * c;
d = sqrt (nd);
if (d * d == nd)
{
cout<< a<< b<< c<< d;
count++;
}
}
}
}
cout<<"Found solutions :"<< count;
}
I want the values of a,b,c,d to be between 0 to (p-1).
I want to output the respective 4 numbers when squared and summed under modulo P make that respective product modulo P
For eg - 1 x 2 x 3 x 4 x 5 mod 100 = 120 mod 100 = ( 8^2 + 6^2 + 4^2 + 2^2 ) mod 100
Note :value of p can be either prime or non-prime.
How do I reflect it in the above code ?

Sum of 4 integers in 4 arrays

Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such that A[i] + B[j] + C[k] + D[l] is zero.
To make problem a bit easier, all A, B, C, D have same length of N where 0 ≤ N ≤ 500. All integers are in the range of -228 to 228 - 1 and the result is guaranteed to be at most 231 - 1.
Example:
Input:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
Output:
2
Explanation:
The two tuples are:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
I just came up with a solution that concatenates all the vectors and find the 4 sum. But I know there is a better solution. Would someone explain a better solution ? I just see codes using O(N^2) but I can't understand it.
This was my O(n^2) solution:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
int n = A.size();
int result = 0;
unordered_map<int,int> sumMap1;
unordered_map<int,int> sumMap2;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) {
int sum1 = A[i] + B[j];
int sum2 = C[i] + D[j];
sumMap1[sum1]++;
sumMap2[sum2]++;
}
}
for(auto num1 : sumMap1) {
int number = num1.first;
if(sumMap2.find(-1 * number) != sumMap2.end()) {
result += num1.second * sumMap2[-1 * number];
}
}
return result;
}
The core observation is - if W + X + Y + Z = 0 then W + X = -(Y + Z).
Here I used two hash-tables for each of possible sums in both (A, B) and (C, D) find number of occurrences of this sum.
Then, for each sum(A, B) we can find if sum(C, D) contains complimentary sum which will ensure sum(A, B) + sum(C, D) = 0. Add (the number of occurrences of sum(a, b)) * (number of occurrences of complimentary sum(c,d)) to the result.
Creating sum(A, B) and sum(C, D) will take O(n^2) time. And counting the number of tuples is O(n^2) as there are n^2 sum for each pairs(A-B, C-D). Other operation like insertion and search on hashtable is amortized O(1). So, the overall time complexity is O(n^2).

C++ Chocolate Puzzle [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
Let's say I have N chocolates that have to be packed into exactly P boxes in the order they arrive. Each chocolate also has a number of calories X and each box has a capacity K which has to be less than or equal to 3*sum(x1, x2, ..., xn) + max(x1, x2, ..., xn)^2 - min(x1, x2, ..., xn)^2.
In the task I'm given N, P and X for each chocolate and I have to figure out the lowest possible K. Could anyone help me on this (not looking for a solution just for some hints regarding the problem)?
Example:
N = 8,
P = 3,
X = {1, 4, 5, 6, 3, 2, 5, 3}
K for first three chocolates = 3*(1+4+5) + 5^2 - 1^2 = 54
K for next two chocolates = 3*(6+3) + 6^2 - 3^2 = 54
K for last three chocolates = 3*(2+5+3) + 5^2 - 2^2 = 51
Lowest possible K = 54
So the goal is to find the best combination using exactly P boxes that has the lowest K.
Thanks!
Here is how I would solve this in Java:
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ChocolatePuzzle {
private static final Map <String, Integer> solutions =
new HashMap <String, Integer> ();
private static final Map <String, Integer> bestMoves =
new HashMap <String, Integer> ();
private static int [] x;
private static int k (int from, int to)
{
int sum = x [from];
int max = x [from];
int min = x [from];
for (int i = from + 1; i < to; i++)
{
sum += x [i];
max = Math.max (max, x [i]);
min = Math.min (min, x [i]);
}
return sum * 3 + max * max - min * min;
}
public static int solve (int n, int p)
{
String signature = n + "," + p;
Integer solution = solutions.get (signature);
if (solution == null)
{
solution = Integer.valueOf (doSolve (n, p, signature));
solutions.put (signature, solution);
}
return solution.intValue ();
}
public static int doSolve (int n, int p, String signature)
{
if (p == 1)
{
bestMoves.put (signature, Integer.valueOf (x.length - n));
return k (n, x.length);
}
else
{
int result = Integer.MAX_VALUE;
int bestMove = 0;
int maxI = x.length - n - p + 1;
for (int i = 1; i <= maxI; i++)
{
int k = Math.max (k (n, n + i), solve (n + i, p - 1));
if (k < result)
{
result = k;
bestMove = i;
}
}
bestMoves.put (signature, Integer.valueOf (bestMove));
return result;
}
}
public static void main(String[] args) {
int n = 20;
int p = 5;
x = new int [n];
Random r = new Random ();
for (int i = 0; i < n; i++)
x [i] = r.nextInt (9) + 1;
System.out.println("N: " + n);
System.out.println("P: " + p);
System.out.print("X: {");
for (int i = 0; i < n; i++)
{
if (i > 0) System.out.print (", ");
System.out.print (x [i]);
}
System.out.println("}");
System.out.println();
int k = solve (0, p);
int o = 0;
for (int i = p; i > 0; i--)
{
int m = bestMoves.get (o + "," + i);
System.out.print ("{");
for (int j = 0; j < m; j++)
{
if (j > 0)
System.out.print (", ");
System.out.print (x [o + j]);
}
System.out.print ("} (k: ");
System.out.print(k (o, o + m));
System.out.println (")");
o += m;
}
System.out.println("min(k): " + k);
}
}
Probably you could find some useful tips in this code.
Sample input:
N: 20
P: 5
X: {1, 7, 6, 6, 5, 5, 7, 9, 1, 3, 9, 5, 3, 7, 9, 1, 4, 2, 4, 8}
Sample output:
{1, 7, 6, 6} (k: 108)
{5, 5, 7, 9} (k: 134)
{1, 3, 9, 5} (k: 134)
{3, 7, 9} (k: 129)
{1, 4, 2, 4, 8} (k: 120)
min(k): 134