Why does a basic optimal variable have positive reduced cost? - linear-programming

Why does a a basic optimal variable have reduced cost positive in a minimization problem?
The lp model is as follows:
\ENCODING=ISO-8859-1
\Problem name: IloCplex
Minimize
obj: 325255008 y(1) + 207016000 y(2) + 511.284124007454 x(1,2,1,2,1,1,1,1,1,1)
+ 511.284124007454 x(1,2,1,2,1,2,1,1,2,2)
+ 511.284124007454 x(1,2,1,2,2,2,2,2,2,2)
+ 511.284124007454 x(1,2,2,3,1,1,2,2,2,2)
+ 511.284124007454 x(1,2,2,3,1,2,2,2,3,3)
+ 511.284124007454 x(1,2,2,3,2,2,3,3,3,3)
+ 511.284124007454 x(1,2,3,1,1,1,3,3,3,3)
+ 511.284124007454 x(1,2,3,1,1,2,3,3,1,1)
+ 511.284124007454 x(1,2,3,1,2,2,1,1,1,1)
+ 511.284124007454 x(2,1,1,2,1,1,2,2,2,2)
+ 511.284124007454 x(2,1,1,2,2,1,1,1,2,2)
+ 511.284124007454 x(2,1,1,2,2,2,1,1,1,1)
+ 511.284124007454 x(2,1,2,3,1,1,3,3,3,3)
+ 511.284124007454 x(2,1,2,3,2,1,2,2,3,3)
+ 511.284124007454 x(2,1,2,3,2,2,2,2,2,2)
+ 511.284124007454 x(2,1,3,1,1,1,1,1,1,1)
+ 511.284124007454 x(2,1,3,1,2,1,3,3,1,1)
+ 511.284124007454 x(2,1,3,1,2,2,3,3,3,3) + 4201096 lambda(1)
+ 8400658 lambda(2) + 21000220 lambda(3)
Subject To
r_beta_1_2: x(1,2,1,2,1,1,1,1,1,1) + x(1,2,1,2,1,2,1,1,2,2)
+ x(1,2,1,2,2,2,2,2,2,2) + x(1,2,2,3,1,1,2,2,2,2)
+ x(1,2,2,3,1,2,2,2,3,3) + x(1,2,2,3,2,2,3,3,3,3)
+ x(1,2,3,1,1,1,3,3,3,3) + x(1,2,3,1,1,2,3,3,1,1)
+ x(1,2,3,1,2,2,1,1,1,1) = 1
r_beta_2_1: x(2,1,1,2,1,1,2,2,2,2) + x(2,1,1,2,2,1,1,1,2,2)
+ x(2,1,1,2,2,2,1,1,1,1) + x(2,1,2,3,1,1,3,3,3,3)
+ x(2,1,2,3,2,1,2,2,3,3) + x(2,1,2,3,2,2,2,2,2,2)
+ x(2,1,3,1,1,1,1,1,1,1) + x(2,1,3,1,2,1,3,3,1,1)
+ x(2,1,3,1,2,2,3,3,3,3) = 1
r_delta_1_2_1: - y(1) + x(1,2,1,2,1,1,1,1,1,1)
+ x(1,2,1,2,1,2,1,1,2,2) + x(1,2,2,3,1,1,2,2,2,2)
+ x(1,2,2,3,1,2,2,2,3,3) + x(1,2,3,1,1,1,3,3,3,3)
+ x(1,2,3,1,1,2,3,3,1,1) <= 0
r_delta_1_2_2: - y(2) + x(1,2,1,2,1,2,1,1,2,2)
+ x(1,2,1,2,2,2,2,2,2,2) + x(1,2,2,3,1,2,2,2,3,3)
+ x(1,2,2,3,2,2,3,3,3,3) + x(1,2,3,1,1,2,3,3,1,1)
+ x(1,2,3,1,2,2,1,1,1,1) <= 0
r_delta_2_1_1: - y(1) + x(2,1,1,2,1,1,2,2,2,2)
+ x(2,1,1,2,2,1,1,1,2,2) + x(2,1,2,3,1,1,3,3,3,3)
+ x(2,1,2,3,2,1,2,2,3,3) + x(2,1,3,1,1,1,1,1,1,1)
+ x(2,1,3,1,2,1,3,3,1,1) <= 0
r_delta_2_1_2: - y(2) + x(2,1,1,2,2,1,1,1,2,2)
+ x(2,1,1,2,2,2,1,1,1,1) + x(2,1,2,3,2,1,2,2,3,3)
+ x(2,1,2,3,2,2,2,2,2,2) + x(2,1,3,1,2,1,3,3,1,1)
+ x(2,1,3,1,2,2,3,3,3,3) <= 0
r_piI_1_2: y(1) + x(1,2,1,2,2,2,2,2,2,2) + x(1,2,2,3,2,2,3,3,3,3)
+ x(1,2,3,1,2,2,1,1,1,1) <= 1
r_piI_2_1: y(2) + x(2,1,1,2,1,1,2,2,2,2) + x(2,1,2,3,1,1,3,3,3,3)
+ x(2,1,3,1,1,1,1,1,1,1) <= 1
r_piJ_1_2: y(2) + x(1,2,1,2,1,1,1,1,1,1) + x(1,2,2,3,1,1,2,2,2,2)
+ x(1,2,3,1,1,1,3,3,3,3) <= 1
r_piJ_2_1: y(1) + x(2,1,1,2,2,2,1,1,1,1) + x(2,1,2,3,2,2,2,2,2,2)
+ x(2,1,3,1,2,2,3,3,3,3) <= 1
r_gamma_1_2_1_2: 17.7232875823975 x(1,2,1,2,1,1,1,1,1,1)
+ 17.7232875823975 x(1,2,1,2,1,2,1,1,2,2)
+ 17.7232875823975 x(1,2,1,2,2,2,2,2,2,2)
- 200 lambda(1) - 300 lambda(2) - 500 lambda(3) <= 0
r_gamma_1_2_2_3: 17.7232875823975 x(1,2,2,3,1,1,2,2,2,2)
+ 17.7232875823975 x(1,2,2,3,1,2,2,2,3,3)
+ 17.7232875823975 x(1,2,2,3,2,2,3,3,3,3) <= 0
r_gamma_1_2_3_1: 17.7232875823975 x(1,2,3,1,1,1,3,3,3,3)
+ 17.7232875823975 x(1,2,3,1,1,2,3,3,1,1)
+ 17.7232875823975 x(1,2,3,1,2,2,1,1,1,1) <= 0
r_gamma_2_1_1_2: 17.7232875823975 x(2,1,1,2,1,1,2,2,2,2)
+ 17.7232875823975 x(2,1,1,2,2,1,1,1,2,2)
+ 17.7232875823975 x(2,1,1,2,2,2,1,1,1,1) <= 0
r_gamma_2_1_2_3: 17.7232875823975 x(2,1,2,3,1,1,3,3,3,3)
+ 17.7232875823975 x(2,1,2,3,2,1,2,2,3,3)
+ 17.7232875823975 x(2,1,2,3,2,2,2,2,2,2)
- 200 lambda(1) - 300 lambda(2) - 500 lambda(3) <= 0
r_gamma_2_1_3_1: 17.7232875823975 x(2,1,3,1,1,1,1,1,1,1)
+ 17.7232875823975 x(2,1,3,1,2,1,3,3,1,1)
+ 17.7232875823975 x(2,1,3,1,2,2,3,3,3,3) <= 0
c17: lambda(1) - Rgc17 = 0
c18: lambda(2) - Rgc18 = 0
c19: lambda(3) - Rgc19 = 0
r_casamento_y_lambda_1: y(1) - lambda(1) - lambda(2) - lambda(3) <= 0
r_casamento_y_lambda_2: y(2) - lambda(1) - lambda(2) - lambda(3) <= 0
Bounds
0 <= y(1) <= 1
0 <= y(2) <= 1
0 <= x(1,2,1,2,1,1,1,1,1,1) <= 1
0 <= x(1,2,1,2,1,2,1,1,2,2) <= 1
0 <= x(1,2,1,2,2,2,2,2,2,2) <= 1
0 <= x(1,2,2,3,1,1,2,2,2,2) <= 1
0 <= x(1,2,2,3,1,2,2,2,3,3) <= 1
0 <= x(1,2,2,3,2,2,3,3,3,3) <= 1
0 <= x(1,2,3,1,1,1,3,3,3,3) <= 1
0 <= x(1,2,3,1,1,2,3,3,1,1) <= 1
0 <= x(1,2,3,1,2,2,1,1,1,1) <= 1
0 <= x(2,1,1,2,1,1,2,2,2,2) <= 1
0 <= x(2,1,1,2,2,1,1,1,2,2) <= 1
0 <= x(2,1,1,2,2,2,1,1,1,1) <= 1
0 <= x(2,1,2,3,1,1,3,3,3,3) <= 1
0 <= x(2,1,2,3,2,1,2,2,3,3) <= 1
0 <= x(2,1,2,3,2,2,2,2,2,2) <= 1
0 <= x(2,1,3,1,1,1,1,1,1,1) <= 1
0 <= x(2,1,3,1,2,1,3,3,1,1) <= 1
0 <= x(2,1,3,1,2,2,3,3,3,3) <= 1
0 <= lambda(1) <= 1
0 <= lambda(2) <= 1
0 <= lambda(3) <= 1
0 <= Rgc17 <= 3
0 <= Rgc18 <= 3
0 <= Rgc19 <= 3
End
I'm worried with lambdas vairables.
When I solve this model directly by the terminal using cplex, I can get this information :
Display which part of the solution: reduced
Display reduced costs for which variable(s): lambda(1)
Variable Name Reduced Cost
lambda(1) -4199562.000000
CPLEX> display solution reduced
Display reduced costs for which variable(s): lambda(2)
The reduced cost 'lambda(2)' is 0.
CPLEX> display solution reduced
Display reduced costs for which variable(s): lambda(3)
Variable Name Reduced Cost
lambda(3) 12599562.000000
CPLEX> display solution variables
Display values of which variable(s): lambda(1)
Variable Name Solution Value
lambda(1) 1.000000
CPLEX> display solution variables
Display values of which variable(s): lambda(2)
The variable 'lambda(2)' is 0.
CPLEX> display solution variables
Display values of which variable(s): lambda(3)
The variable 'lambda(3)' is 0.
Is that ok?

A variable can be non-basic if it is at one of its bounds (i.e. lower-bound or upper-bound). (Detail: free variable are special: they can be nonbasic between bounds -- sometimes called superbasic). So all variables λ are potentially non-basic when we look at the values. The reduced cost indicate that λ1 and λ3 must be non-basic and λ2 can be basic or non-basic (if the solution is degenerate). Use display solution basis to find all basic variables.
The sign of the reduced cost depends if the variable is nonbasic upper or nonbasic lower. It basically indicates how the objective can change if the corresponding bound changes. A positive rc for λ3 looks fine to me. (It is non-basic and not basic as you seem to think).

Related

Why can't the subs function of the sympy replace the value of the symbol sometimes?

I have the following code:
u_ini = 0.1
v_ini = 0.1
z_ini = 0.1 # 初始化三个拉格朗日乘子
q = 0
lis = list(range(2))
u = list(sp.symbols('u:{}'.format(len(lis))))
v = list(sp.symbols('v:{}'.format(len(lis))))
z = sp.symbols('z')
p = list(sp.symbols('p:{}'.format(len(lis))))
lag1 = 0
lag2 = 0
lag3 = 0
p_symbol_sum = np.sum(p)
for i in range(k):
if i < k-1:
lag1 += B*ts_ratio[i]*sp.log(1+g[i]*p[i]/(sgm_2+g[i]*np.sum(p[i+1:k])),2)-q*(af_eff*p[i]+Pc-eh_eff*(1-ts_ratio[i])*g[i]*p_symbol_sum)
lag2 -= u[i] * (R_min - ts_ratio[i] * B * sp.log(1 + g[i] * p[i] / (sgm_2 + g[i] * np.sum(p[i + 1:k])),2))
elif i == k-1:
lag1 += B*ts_ratio[i]*sp.log(1+g[i]*p[i]/(sgm_2+g[i]*p[i]),2)-q*(af_eff*p[i]+Pc-eh_eff*(1-ts_ratio[i])*g[i]*p_symbol_sum)
lag2 -= u[i] * (R_min - ts_ratio[i] * B * sp.log(1+g[i]*p[i]/(sgm_2+g[i]*p[i]),2))
lag3 -= v[i] * (E_min - (1 - ts_ratio[i])*eh_eff*g[i]*p_symbol_sum) + z * (p[i] - p_max)
lag_fun = lag1 + lag2 + lag3
print("lag_fun:",lag_fun)
for i in range(k):
lag_fun.subs([(u[i],u_ini), (v[i],v_ini), (z,z_ini), (p[i],p_ini)]).evalf()
print("lag_fun:",lag_fun)
Why does the value of the expression not change after I count down the subs of the second line。
This is the output of the program. The first line is the output before using subs. The second is the output after using subs. Why hasn't it changed?
lag_fun: -u0*(-0.5*log(0.0410609879149758*p0/(0.0410609879149758*p1 + 0.001) + 1)/log(2) + 2) - u1*(-0.5*log(0.0123909311217172*p1/(0.0123909311217172*p1 + 0.001) + 1)/log(2) + 2) - v0*(-0.00205304939574879*p0 - 0.00205304939574879*p1 + 0.2) - v1*(-0.000619546556085859*p0 - 0.000619546556085859*p1 + 0.2) - z*(p0 - 20) - z*(p1 - 20) + 0.5*log(0.0410609879149758*p0/(0.0410609879149758*p1 + 0.001) + 1)/log(2) + 0.5*log(0.0123909311217172*p1/(0.0123909311217172*p1 + 0.001) + 1)/log(2)
lag_fun: -u0*(-0.5*log(0.0410609879149758*p0/(0.0410609879149758*p1 + 0.001) + 1)/log(2) + 2) - u1*(-0.5*log(0.0123909311217172*p1/(0.0123909311217172*p1 + 0.001) + 1)/log(2) + 2) - v0*(-0.00205304939574879*p0 - 0.00205304939574879*p1 + 0.2) - v1*(-0.000619546556085859*p0 - 0.000619546556085859*p1 + 0.2) - z*(p0 - 20) - z*(p1 - 20) + 0.5*log(0.0410609879149758*p0/(0.0410609879149758*p1 + 0.001) + 1)/log(2) + 0.5*log(0.0123909311217172*p1/(0.0123909311217172*p1 + 0.001) + 1)/log(2)
subs doesn't change anything in place, you have to capture the result for the same reason that this loop fails to change x:
>>> x = 0
>>> for i in range(10): x + 1
>>> x
0
So it must be
lag_fun = lag_fun.subs(etc...)

Calculating time complexity of a recursive function having a loop inside it

I was working on a simple problem and I came up with a recursive function in C++, below is my function.
void test(int arr[],int n,int x = 0){
cout<<arr[x];
for(int i = x+1;i < n;i++){
test(arr, n, i);
}
}
I wonder what will be the time complexity of the above function if anyone can calculate the time complexity for the above method it will be a great help in improving my function.
You can write its recurrent relation likes the following:
T(n) = T(n-1) + T(n-2) + ... + T(1) + 1
Indeed T'(x) is T(n - x) and T(1) = 1 (The last one in the realtion is is for cout). We can see:
T(2) = T(1) + 1 = 2
T(3) = T(2) + T(1) + 1 = 2 + 1 + 1 = 4
T(4) = 4 + 2 + 1 + 1 = 2^2 + 2^1 + 2^0 + 1 = 8
T(5) = 8 + 4 + 2 + 1 + 1 = 2^3 + 2^2 + 2^1 + 2^0 + 1 = 16
.
.
.
T(n) = 2^{n-2} + 2^{n-1} + ... + 2^0 + 1 = 2^{n-1}
Hence, T(n) = \Theta(2^n).

Sum of increasing alternate terms in python

I need to evaluate the finite sum of numbers which are increasing in absolute value, but are alternate. Problem is: the abolute values grow too fast and it starts accumulating numerical errors. These the functions definitions, one (Gj_full) straight to it and the other (Gj) recursively. fact_quo is a simple factorial function.
def fact_quo(n, m=1):
if (type(n) != int) or (type(m) != int):
raise TypeError("Arguments must be integers.")
if (n < 0) or (m < 0):
raise ValueError("n=" + str(n) + "\t m=" + str(m))
if (n == 0) or (n == 1) or (n == m):
return 1
if (n < m):
raise ValueError("n=" + str(n) + "\t m=" + str(m))
f = n
while n > (m+1):
n -= 1
f *= n
return f
def Gj_full(X, Y, Xl, Yl, j=0, coef=1):
if (X - Y + Xl + Yl) % 2 or X < Y or Y < j:
raise ValueError
u = (X - Y + Xl + Yl) // 2
v = coef * (2 ** (X - Y) * fact_quo(X, Y-j) * fact_quo(u+j, j) *
4 ** j * (-1) ** j)
w = 3 ** (u+j) * fact_quo(X-Y+j)
den2 = fact_quo(X) * fact_quo(Xl) * fact_quo(Yl)
z = (np.sqrt(fact_quo(X)) * np.sqrt(fact_quo(Y))
* np.sqrt(fact_quo(Xl)) * np.sqrt(fact_quo(Yl)))
return (v / (den2 * w)) * z
def Gj(X, Y, Xl, Yl, j=0, coef=1):
if (X - Y + Xl + Yl) % 2 or X < Y or Y < j:
raise ValueError
kX, kY, kXl, kYl, kj = X % 2, Y % 2, Xl % 2, Yl % 2, 0
g = coef * Gj_full(kX, kY, kXl, kYl, kj)
while kX < X:
u = (kX - kY + kXl + kYl) // 2
v = 4 * (u + kj + 1)
w = 3 * (kX + 2 - kY + kj) * (kX + 1 - kY + kj)
g *= (v / w) * np.sqrt(kX + 2) * np.sqrt(kX + 1)
kX += 2
while kXl < Xl:
u = (kX - kY + kXl + kYl) // 2
v = u + kj + 1
w = 3 * (kXl + 2) * (kXl + 1)
g *= (v / w) * np.sqrt(kXl + 2) * np.sqrt(kXl + 1)
kXl += 2
while kYl < Yl:
u = (kX - kY + kXl + kYl) // 2
v = u + kj + 1
w = 3 * (kYl + 2) * (kYl + 1)
g *= (v / w) * np.sqrt(kYl + 2) * np.sqrt(kYl + 1)
kYl += 2
while kY < Y:
u = (kX - kY + kXl + kYl) // 2
v = 3 * (kX - kY + kj) * (kX - kY - 1 + kj)
w = 4 * (kY + 2 - kj) * (kY + 1 - kj) * (u + kj)
g *= (v / w) * np.sqrt(kY + 2) * np.sqrt(kY + 1)
kY += 2
while kj < j:
u = (kX - kY + kXl + kYl) // 2
v = -4 * (kY - kj) * (u + kj + 1)
w = 3 * (kX - kY + kj + 1) * (kj + 1)
g *= (v / w)
kj += 1
return g
The (4/3) ** j and the factorials quicly increase the absolute value of the summing terms. The sum, however, are supposed to be smaller than 1. In fact, for X = Y and Xl = Yl = 0, the sum equals to (-1/3) ** X.
The precision for infinitely large numbers for floats are not available yet without using a lib. Therefore you should look into the decimal lib, you can even set the precision. Eg.
import decimal
decimal.getcontext().prec = 100
def pi():
pi = decimal.Decimal(0)
for k in range(350):
pi += (decimal.Decimal(4)/(decimal.Decimal(8)*decimal.Decimal(k+1))...)
If you manage to force all the numbers to be integers, you don't need to worry about it

Catalan Numbers, Recursive function time complexity

The following function produces the nth number in catalan numbers. What is the exact time complexity function of this function or how can I find it myself?
int catalan(int n)
{
if (n==0 || n==1)
return 1;
int sum = 0;
for(int i=1;i<n;i++)
sum += catalan(i)*catalan(n-i);
return sum;
}
Note: I know this is the worst possible way to compute a catalan number.
To evaluate the complexity, let us focus on the number of recursive calls performed, let C(n).
A call for n implies exactly 2(n-1) recursive calls, each of them adding their own costs, 2(C(1)+C(2)+...C(n-1)).
A call for n+1 implies exactly 2n recursive calls, each of them adding their own costs, 2(C(1)+C(2)+...C(n-1)+C(n)).
By difference, C(n+1)-C(n) = 2+2C(n), which can be written C(n) = 2+3C(n-1).
C(1) = 0
C(2) = 2+2C(1) = 2+3C(0) = 2
C(3) = 4+2(C(1)+C(2)) = 2+3C(2) = 8
C(3) = 6+2(C(1)+C(2)+C(3)) = 2+3C(3) = 26
C(4) = 8+2(C(1)+C(2)+C(3)+C(4)) = 2+3C(4) = 80
...
C(n) = 2n-2+2(C(1)+C(2)+...C(n-1)) = 2+3C(n-1)
To solve this recurrence easily, notice that
C(n)+1 = 3(C(n-1)+1) = 9(C(n-2)+1) = ...3^(n-2)(C(2)+1) = 3^(n-1)
Hence, for n>1 the exact formula is
C(n) = 3^(n-1)-1
The number of calls to Catalan(1) (constant time), is also C(n), and the numbers of adds or multiplies are C(n)/2 each.
It is easy to reduce the complexity from O(3^n) to O(2^n) by noting that all terms in the loop (except the middle one) are computed twice - but that still doesn't make it an acceptable implementation :)
Assume
any step other than for-loop is k;
summation and multiple in for-loop is c and
catalan(r) is T(r)
In the for-loop of catalan(n), catalan(i) performs n-1 times where value of i from 1 to n-1 and catalan(n-i) performs n-1 times where value of n-i from n-1 to 1. In short, catalan(i) and catalan(n-i) equals to two times all catalan(x) where value of x from 1 to n-1.
T(n) = 2(T(1) + T(2) + T(3) + ... + T(n-2) + T(n-1)) + k + (n-1)c
Similarly,
T(n-1) = 2(T(1) + T(2) + T(3) + ... + T(n-2)) + k + (n-2)c
Reorder T(n) as 2(T(1) + T(2) + T(3) + ... + T(n-2)) + 2T(n-1) + k + (n-2)c + c
T(n) = 2(T(1) + T(2) + T(3) + ... + T(n-2)) + k + (n-2)c + 2T(n-1) + c
T(n) = T(n-1) + 2T(n-1) + c
T(n) = 3T(n-1) + c
T(n) = (3^2)T(n-2) + 3c + c
T(n) = (3^3)T(n-3) + (3^2)c + 3c + c
and so on...
T(n) = (3^(n-1))T(n-(n-1)) + c(3^0 + 3^1 + 3^2 + ... + 3^(n-2))
T(n) = (3^(n-1))T(1) + ((3^(n-1)-1)/2)c
So, the time complexity is O(3 ^ N)
My process is quite similar to #hk6279's one but I believe easier to understand because I start from the code itself. I start defining the recurrence relation as it is in code and then substitute it.
I also remove all the + k + c variables from #hk6279's approach because it adds noise to the equation and at the end all those variables will be ruled out.
Recurrence relation
T(n) => 1 -> n = 1
T(i) * T(n-i) -> n > 1; for i in 1..n-1
Visualize when n > 1
T(n) = [T(1) + T(2) + T(3) + .... + T(n-2) + T(n-1)] + [T(n-1) + T(n-2) + .... + T(3) + T(2) + T(1)]
T(n) = [T(1) + T(2) + T(3) + .... + T(n-2) + T(n-1)] + [T(1) + T(2) + T(3) + .... + T(n-2) + T(n-1)]
T(n) = 2 * [T(1) + T(2) + T(3) + .... + T(n-2) + T(n-1)]
What is T(n-1) ?
T(n-1) = 2 * [T(1) + T(2) + T(3) + .... + T(n-2)]
Replace with T(n-1)
T(n) = 2 * [T(1) + T(2) + T(3) + .... + T(n-2) + T(n-1)]
T(n) = 2 * [T(1) + T(2) + T(3) + .... + T(n-2)] + 2 * [T(n-1)]
T(n) = T(n-1) + 2 * [T(n-1)]
T(n) = 3 * T(n-1)
What is T(n-2) ?
T(n-2) = 2 * [T(1) + T(2) + T(3) + .... + T(n-3)]
Replace with T(n-2)
T(n) = 3 * [2 * [T(1) + T(2) + T(3) + .... + T(n-3) + T(n-2)]]
T(n) = 3 * [2 * [T(1) + T(2) + T(3) + .... + T(n-3)] + 2 * T(n-2)]]
T(n) = 3 * [T(n-2) + 2*T(n-2)]
T(n) = 3 * [3 * T(n-2)]
T(n) = 3^2 * T(n-2)
Replace with T(n-k)
T(n) = 3^k * T(n-k)
if n - k = 1 => k = n + 1
T(n) = 3^(n+1) * T(n-n+1)
T(n) = 3^(n+1) * T(1)
T(n) = 3^(n+1) * 1
Time complexiTy
O(3^n)

gurobi - Error code = 10004 Unable to retrieve attribute 'X'

I am getting an error in my c++/gurobi file:
Error code = 10004 Unable to retrieve attribute 'X'
I read that this might have something to do with labels? But I don't see how there is a problem.
It works for some input files, but not for others. So I have created a toy file, t5.txt in attachment. This file does not work, but removing the last column and setting 8 to 7 fixes it. I am puzzled...
Below is the output of model.write. Everything seems to make sense, any Ideas what I am doing wrong?
Whenever I do a model.write(test.sol), the program stops, so there seems to be something wrong with the solution>
Attachments:
main.cpp -> https://dl.dropboxusercontent.com/u/13564139/main.cpp
input.txt -> https://dl.dropboxusercontent.com/u/13564139/t5.txt
Maximize
15 student_has_projects4.1
Subject To
R0: student_has_projects0.0 + student_has_projects1.0
+ student_has_projects2.0 + student_has_projects3.0
+ student_has_projects4.0 + student_has_projects5.0
+ student_has_projects6.0 + student_has_projects7.0 <= 4
R1: student_has_projects1.0 + student_has_projects2.0 >= 1
R2: student_has_projects2.0 + 2 student_has_projects5.0 <= 2
R3: student_has_projects2.0 + 2 student_has_projects5.0 >= 1
R4: student_has_projects0.0 + student_has_projects3.0
+ student_has_projects4.0 + student_has_projects6.0
+ student_has_projects7.0 >= 1
R5: student_has_projects2.0 + student_has_projects5.0 <= 1
R6: student_has_projects0.1 + student_has_projects1.1
+ student_has_projects2.1 + student_has_projects3.1
+ student_has_projects4.1 + student_has_projects5.1
+ student_has_projects6.1 + student_has_projects7.1 <= 4
R7: student_has_projects1.1 + student_has_projects2.1 >= 1
R8: student_has_projects2.1 + 2 student_has_projects5.1 <= 2
R9: student_has_projects2.1 + 2 student_has_projects5.1 >= 1
R10: student_has_projects0.1 + student_has_projects3.1
+ student_has_projects4.1 + student_has_projects6.1
+ student_has_projects7.1 >= 1
R11: student_has_projects2.1 + student_has_projects5.1 <= 1
R12: student_has_projects0.2 + student_has_projects1.2
+ student_has_projects2.2 + student_has_projects3.2
+ student_has_projects4.2 + student_has_projects5.2
+ student_has_projects6.2 + student_has_projects7.2 <= 4
R13: student_has_projects1.2 + student_has_projects2.2 >= 1
R14: student_has_projects2.2 + 2 student_has_projects5.2 <= 2
R15: student_has_projects2.2 + 2 student_has_projects5.2 >= 1
R16: student_has_projects0.2 + student_has_projects3.2
+ student_has_projects4.2 + student_has_projects6.2
+ student_has_projects7.2 >= 1
R17: student_has_projects2.2 + student_has_projects5.2 <= 1
R18: student_has_projects0.0 + student_has_projects0.1
+ student_has_projects0.2 = 1
R19: student_has_projects1.0 + student_has_projects1.1
+ student_has_projects1.2 = 1
R20: student_has_projects2.0 + student_has_projects2.1
+ student_has_projects2.2 = 1
R21: student_has_projects3.0 + student_has_projects3.1
+ student_has_projects3.2 = 1
R22: student_has_projects4.0 + student_has_projects4.1
+ student_has_projects4.2 = 1
R23: student_has_projects5.0 + student_has_projects5.1
+ student_has_projects5.2 = 1
R24: student_has_projects6.0 + student_has_projects6.1
+ student_has_projects6.2 = 1
R25: student_has_projects7.0 + student_has_projects7.1
+ student_has_projects7.2 = 1
Bounds
Binaries
student_has_projects0.0 student_has_projects0.1 student_has_projects0.2
student_has_projects1.0 student_has_projects1.1 student_has_projects1.2
student_has_projects2.0 student_has_projects2.1 student_has_projects2.2
student_has_projects3.0 student_has_projects3.1 student_has_projects3.2
student_has_projects4.0 student_has_projects4.1 student_has_projects4.2
student_has_projects5.0 student_has_projects5.1 student_has_projects5.2
student_has_projects6.0 student_has_projects6.1 student_has_projects6.2
student_has_projects7.0 student_has_projects7.1 student_has_projects7.2
End
The issue is that your lp instance is infeasible so the call to .optimize() results in an infeasible status. From your code
model.write("test2.lp");
model.optimize();
model.write("forum2.sol");
if(model.get(GRB_IntAttr_Status) != GRB_OPTIMAL){
cout << "niet optimaal " << endl;
}
You are writing a .sol file before you check for success. Gurobi gets the 'X' attributes from the variables when it writes a .sol file. If the optimization fails, the 'X' attributes aren't available and an exception is thrown. You should make sure that gurobi has a solution before you write a .sol file, or get many attributes, including 'X', 'Pi' and 'ObjVal'. The OPTIMAL status codes assures you that that there is an available solution, but codes like SUBOPTIMAL also indicate that there is a solution available and others like TIME_LIMIT, NODE_LIMIT mean there might be a solution available. You can get the attribute SolCount to get a definitive indication that there is a solution available.
Your problem instance is infeasible because constraints (R1, R7, R13 imply you need at least 3 projects for students 1 and 2, but constraints (R19, R20) imply they can have exactly 1 project each. You can see this by using the IIS solver. In interactive gurobi you can get get an Irreducible Inconsistent Subsystem
m = read("test2.lp")
m.optimize()
m.computeIIS()
m.write("test2.ilp")