-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkiwiel.py
127 lines (105 loc) · 3.31 KB
/
kiwiel.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"""
This script contains the method kiwiel, which solves Knapsack problem.
This code corresponds to PEP8 standard's requirements.
"""
import numpy as np
from math import ceil
import logging
from random import random
from functools import reduce
logging.basicConfig(
format='%(levelname)s [%(module)s]: %(message)s'
)
_logger = logging.getLogger(__name__)
_logger.setLevel(logging.INFO)
'''
Knapsack problem:
min 0.5 x'Dx-a'x
s.t.: b'x=r, l<=x<=u
Matrix D=diag(d), with d>0 (convex objective function)
K.C. Kiwiel,
On Linear-Time Algorithms for the Continuous Quadratic Knapsack Problem,
J. Optim Theory Appl (2007) 134: 549–554.
where:
n - scalar: dimension
r - scalar
D - array of size nx1
a - array of size nx1
b - array of size nx1
u - array of size nx1 (upper limit)
l - array of size nx1 (lower limit)
'''
def kiwiel(n, r, D, a, b, u, l):
dim = 2 * n
Ind = [i for i, b_val in enumerate(b) if b_val < 0]
lold = list(l)
a = np.asarray([b_sig * a_val for a_val, b_sig in zip(a, np.sign(b))])
b = np.asarray([b_sig * b_val for b_val, b_sig in zip(b, np.sign(b))])
for i in Ind:
l[i] = -u[i]
u[i] = -lold[i]
tl = []
tu = []
for i in range(n):
tl_val = (a[i][0] - l[i][0] * D[i][0]) / b[i][0]
tu_val = (a[i][0] - u[i][0] * D[i][0]) / b[i][0]
tl.append(tl_val)
tu.append(tu_val)
tL = min(tu)
tU = max(tl)
T = tl + tu
while(dim > 0):
ran = int(random() * dim)
tmed1 = T[ran]
gt = gfunc(n, D, a, b, u, l, tmed1, tL, tU)
if gt == r:
tstar = tmed1
_logger.info("Break was called")
break
elif gt > r:
tL = tmed1
T = [t_it for t_it in T if t_it > tmed1]
dim = len(T)
else:
tU = tmed1
T = [t_it for t_it in T if t_it < tmed1]
dim = len(T)
p = 0
q = 0
s = 0
for i in range(n):
if tl[i] <= tL:
s = s + b[i][0] * l[i][0]
if tu[i] >= tU:
s = s + b[i][0] * u[i][0]
if (tu[i] <= tL) and (tL <= tl[i]) and (tu[i] <= tU) \
and (tU <= tl[i]):
p = p + a[i][0] * b[i][0] / D[i][0]
q = q + b[i][0] * b[i][0] / D[i][0]
if p == s == r == q == 0:
tstar = None
else:
tstar = (p + s - r) / q
xtstar = np.zeros((n, 1))
for i in range(n):
if tstar <= tu[i]:
xtstar[i][0] = u[i][0]
elif tu[i] <= tstar and tstar <= tl[i]:
xtstar[i][0] = (a[i][0] - tstar * b[i][0]) / D[i][0]
elif tl[i] <= tstar:
xtstar[i][0] = l[i][0]
for i in Ind:
xtstar[i][0] = -xtstar[i][0]
return xtstar
def gfunc(n, D, a, b, u, l, t, tL, tU):
gt = 0
for i in range(n):
tli = (a[i][0] - l[i][0] * D[i][0]) / b[i][0]
tui = (a[i][0] - u[i][0] * D[i][0]) / b[i][0]
if t <= tui:
gt = gt + b[i][0] * u[i][0]
elif tui <= t and t <= tli:
gt = gt + b[i][0] * (a[i][0] - t * b[i][0]) / D[i][0]
elif tli <= t:
gt = gt + b[i][0] * l[i][0]
return gt