냅삭 문제의 결과 그림
소개
"조합 최적화를 사용합시다."에서 냅삭 문제의 해법으로서, "탐욕법은 좋은 방법인 최적이 아니다"라고 말했습니다.
사실, 어떨까라고 생각했기 때문에 확인해 보겠습니다.
무작위 문제를 파이썬으로 해결
데이터 준비
파이썬%matplotlib inline
import math, numpy as np, matplotlib.pyplot as plt
from pulp import *
np.random.seed(1)
n = 100 # アイテム数
siz = np.random.uniform(0.1, 1.0, n)
prf = siz * np.random.lognormal(1, 0.1, n)
eff = prf / siz
siz, prf, eff = np.array([siz, prf, eff]).T[eff.argsort()].T
r1, r2, p1, p2 = [], [], [], []
근사 해법 (탐욕법) 결과
탐욕법에서는 효율(가치/크기)의 좋은 순서로 조사해 가고 용량을 초과하지 않도록 넣습니다.
파이썬for sz in range(math.ceil(sum(siz)*10)):
v, r, rm = 0, [], sz / 10
for i in range(len(siz)-1, -1, -1):
r.append(int(rm < siz[i]))
if r[-1] == 0:
rm -= siz[i]
v += prf[i]
r1.append(list(reversed(r)))
p1.append(v)
plt.imshow(np.array(r1).T, cmap='gray')
%matplotlib inline
import math, numpy as np, matplotlib.pyplot as plt
from pulp import *
np.random.seed(1)
n = 100 # アイテム数
siz = np.random.uniform(0.1, 1.0, n)
prf = siz * np.random.lognormal(1, 0.1, n)
eff = prf / siz
siz, prf, eff = np.array([siz, prf, eff]).T[eff.argsort()].T
r1, r2, p1, p2 = [], [], [], []
탐욕법에서는 효율(가치/크기)의 좋은 순서로 조사해 가고 용량을 초과하지 않도록 넣습니다.
파이썬
for sz in range(math.ceil(sum(siz)*10)):
v, r, rm = 0, [], sz / 10
for i in range(len(siz)-1, -1, -1):
r.append(int(rm < siz[i]))
if r[-1] == 0:
rm -= siz[i]
v += prf[i]
r1.append(list(reversed(r)))
p1.append(v)
plt.imshow(np.array(r1).T, cmap='gray')
엄밀한 해법의 결과
pulp에서 혼합 정수 최적화 문제로 풀어 봅시다.
파이썬m = LpProblem(sense=LpMaximize)
v = [LpVariable('v%d'%i, cat=LpBinary) for i in range(len(siz))]
m += lpDot(prf, v)
e = lpDot(siz, v) <= 1
m += e
r = []
for sz in range(math.ceil(sum(siz)*10)):
e.changeRHS(sz / 10)
m.solve()
r2.append([1 - int(value(x)) for x in v])
p2.append(value(m.objective))
plt.imshow(np.array(r2).T, cmap='gray')
m = LpProblem(sense=LpMaximize)
v = [LpVariable('v%d'%i, cat=LpBinary) for i in range(len(siz))]
m += lpDot(prf, v)
e = lpDot(siz, v) <= 1
m += e
r = []
for sz in range(math.ceil(sum(siz)*10)):
e.changeRHS(sz / 10)
m.solve()
r2.append([1 - int(value(x)) for x in v])
p2.append(value(m.objective))
plt.imshow(np.array(r2).T, cmap='gray')
탐욕법의 정확성
탐욕법의 해의 값을 엄밀해의 값으로 나눈 것을 그래프화합니다. 세로가 비로, 가로가 냅삭의 용량×10입니다.
파이썬plt.ylim((0, 1.1))
plt.plot(np.array(p1[2:]) / np.array(p2[2:]))
용량이 작고, 들어가는 아이템수가 적으면, 다소, 오차가 있습니다만, 어느 정도의 아이템수가 있으면, 꽤 정밀도가 좋은 것을 알 수 있습니다.
추기(吝嗇法)
H22.Math.Prog.No.9.pdf 에 있던 吝嗇法을 시험해 보았습니다.
파이썬r3,p3 = [],[]
for sz in range(math.ceil(sum(siz)*10)):
v, r, ca, rm = 0, [], sz / 10, sum(siz)
for i in range(len(siz)):
r.append(int(not(0 < rm-siz[i] <= ca and siz[i] <= ca)))
rm -= siz[i]
if r[-1] == 0:
ca -= siz[i]
v += prf[i]
r3.append(r)
p3.append(v)
plt.imshow(np.array(r3).T, cmap='gray');
탐욕법은 경계 위로 튀어나왔지만, 吝嗇法은 경계 아래에 빠진 것이 있음을 알 수 있습니다.
성능을 보면 탐욕법보다 나쁜 느낌입니다.
파이썬plt.ylim((0, 1.1))
plt.plot(np.array(p3[2:]) / np.array(p2[2:]));
이상
Reference
이 문제에 관하여(냅삭 문제의 결과 그림), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/SaitoTsutomu/items/ce0d17b15a0226c94a0e
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
plt.ylim((0, 1.1))
plt.plot(np.array(p1[2:]) / np.array(p2[2:]))
H22.Math.Prog.No.9.pdf 에 있던 吝嗇法을 시험해 보았습니다.
파이썬
r3,p3 = [],[]
for sz in range(math.ceil(sum(siz)*10)):
v, r, ca, rm = 0, [], sz / 10, sum(siz)
for i in range(len(siz)):
r.append(int(not(0 < rm-siz[i] <= ca and siz[i] <= ca)))
rm -= siz[i]
if r[-1] == 0:
ca -= siz[i]
v += prf[i]
r3.append(r)
p3.append(v)
plt.imshow(np.array(r3).T, cmap='gray');
탐욕법은 경계 위로 튀어나왔지만, 吝嗇法은 경계 아래에 빠진 것이 있음을 알 수 있습니다.
성능을 보면 탐욕법보다 나쁜 느낌입니다.
파이썬
plt.ylim((0, 1.1))
plt.plot(np.array(p3[2:]) / np.array(p2[2:]));
이상
Reference
이 문제에 관하여(냅삭 문제의 결과 그림), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/SaitoTsutomu/items/ce0d17b15a0226c94a0e텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)