ナップサック問題とその変形

準備

整数ナップサック問題に対する動的最適化

最初に考えるのは整数ナップサック問題(integer knapsack problem)とよばれる問題である.

$n$ 個のアイテムから成る有限集合 $N$, 各々の $i \in N$ の重量 $s_i \in \mathbf{Z}_+$ と価値 $v_i \in \mathbf{Z}_+$, およびナップサックの重量の上限 $b \in \mathbf{Z}_+$ が与えられたとき, アイテムの重量の合計が $b$ を超えないようなアイテムの詰め合わせの中で, 価値の合計が最大のものを求めよ.ただし,各アイテムは何個でもナップサックに詰めて良いものと仮定する.

この問題は,非負の整数の値をとる変数 $x_i \in \{0,1,2,\cdots\}=\mathbf{Z}_+$ を用いて,以下のように定式化できる. $$ \begin{array}{l l l} maximize & \sum_{i \in N} v_i x_i & \\ s.t. & \sum_{i \in N} s_i x_i \leq b & \\ & x_i \in \mathbf{Z}_+ & i \in N \end{array} $$

動的最適化の特徴は,自明な部分問題からはじめて順次大きな部分問題を解いていく点にある. 整数ナップサック問題の場合には,ナップサックの重量上限を制限した部分問題を考えれば良い.

ナップサックに入っているアイテムの重量が $\theta ~(=0,1,2,\cdots,b)$ 以下のときの最大価値を $f(\theta)$ と書くことにしよう. もとの問題の最適値は,重量が $b$ 以下の中で最大の価値であるから $f(b)$ である.

$f(0)=0$ は自明であり,さらに $f(b)=-\infty ~(b<0)$ と定義しておく. $f(\theta)$ は,$\theta$ から $s_i$ だけ軽い重量が詰まっているナップサックにおける最大価値 $f(\theta-s_i)$ に $v_i$ の価値を加えることによって得られる最大の価値であるので, $$ f(\theta) = \max_{i \in N} \left\{ f(\theta - s_i)+v_i, 0 \right\} \ \ \ \theta =1,2,\ldots,b $$ の関係式が得られる.これが再帰方程式になる.

再帰方程式を辞書によるメモ化によって高速化したものが,動的最適化アルゴリズムである. 辞書に,ナップサックに入れたアイテムの情報を保管することによって,最適解も得ることができる.

このアルゴリズムは,各 $\theta (=0,1,\ldots,b)$ に対してアイテムの数 $n$ だけの計算時間がかかるので, 全体として $O(n b)$ 時間かかる.

この計算時間は,一見すると入力サイズの多項式関数に見えるが, 実はナップサックの重量の上限 $b$ の正確な入力サイズは,$b$ でなく $\lceil \log_2 b \rceil$ なのである. ここで $\lceil \cdot \rceil$ は天井関数(ceiling function)であり,$\cdot$ 以上の最小の整数(切り上げ)を意味する. $\lceil \log_2 b \rceil$ を $\beta$ とおくと,動的計画アルゴリズムの計算時間は $O(n 2^{\beta})$ となる. これは,正確な入力サイズ $\beta$ 多項式関数ではない. ちなみに, このようなアルゴリズムを擬多項式時間(pseudo-polynomial time)アルゴリズムとよぶ.

再帰方程式をコードにすると以下のように書ける.

def ikpdp(s, v, b):
    def f(b):
        if b == 0:
            return 0, -1
        if b < 0:
            return -999999, -1
        if b in memo:
            return memo[b]
        else:
            max_value = 0
            prev = -1
            for i, size in enumerate(s):
                if f(b - size)[0] + v[i] > max_value:
                    max_value = f(b - size)[0] + v[i]
                    prev = i
            memo[b] = max_value, prev
        return memo[b]

    memo = {}
    opt_val, prev = f(b)
    x = [0 for i in range(len(s))]
    while True:
        val, prev = memo[b]
        x[prev] += 1
        b -= s[prev]
        if b <= 0:
            break

    return opt_val, x
s = [2, 3, 4, 5]
v = [16, 19, 23, 28]
b = 7
opt_val, x = ikpdp(s, v, b)
print("Opt. value=", opt_val)
print("Sol.=", x)
Opt. value= 51
Sol.= [2, 1, 0, 0]

0-1ナップサック問題に対する動的最適化

この問題は上で考えた整数ナップサック問題とほぼ同じであるが,各アイテムが $1$個ずつしかない点が異なる.,

$n$個のアイテムから成る有限集合 $N$, 各々の $i \in N$ の重量 $s_i \in \mathbf{Z}_+$ と価値 $v_i \in \mathbf{Z}_+$, およびナップサックの重量の上限 $b \in \mathbf{Z}_+$ が与えられたとき, アイテムの重量の合計が $b$ を超えないようなアイテムの詰め合わせの中で, 価値の合計が最大のものを求めよ.ただし,各アイテムはナップサックに高々$1$個しか詰めることができないと仮定する.

$0$-$1$ナップサック問題は,アイテム $i (\in N)$ をナップサックに詰めるとき $1$, それ以外のとき $0$ になる $0$-$1$ 変数$x_i$を使うと,以下の$0$-$1$整数最適化問題として定式化できる. $$ \begin{array}{l l l} maximize & \sum_{i \in N} v_i x_i & \\ s.t. & \sum_{i \in N} s_i x_i \leq b & \\ & x_i \in \{0,1\} & i \in N \end{array} $$

再帰方程式を得るために, ナップサックに入れる対象を $k$番目までのアイテムに限定したとき, 重量の上限が $\theta$ 以下で価値の合計の最大のものを求める部分問題を考え,その最適値を $f(k,\theta)$ とする. もとの問題の最適値は $f(n,b)$ で計算できる.

部分問題間の関係より,$f(k,\theta)$ は,以下の再帰方程式によって計算可能である. $$ f(k,\theta) = \left\{ \begin{array}{ll} f(k-1,\theta) & 0 \leq \theta < s_k \\ \max \left\{ f(k-1,\theta), v_k + f(k-1, \theta - s_k) \right\} & s_k \leq \theta \end{array} \right\} k=1,2, \ldots,n $$

上の再帰方程式を条件 $$ f(0, \theta)= \left\{ \begin{array}{ll} 0 & 0 \leq \theta < s_0 \\ v_0 & s_0 \leq \theta \leq b \end{array} \right. $$ の下で解くことによって $f(k,\theta)$ を $O(k \theta)$時間で得ることができる. したがって,$0$-$1$ナップサック問題の最適値を $O(n b)$ 時間で求めることができる.

def kpdp(s, v, b):
    def f(k, b):
        if b < 0:
            return -9999, 0
        if k == 0:
            if b >= s[0]:
                memo[0, b] = v[0], 1
                return memo[0, b]
            else:
                return 0, 0
        if (k, b) in memo:
            return memo[k, b]
        else:
            if f(k - 1, b)[0] < f(k - 1, b - s[k])[0] + v[k]:
                max_value = f(k - 1, b - s[k])[0] + v[k]
                sol = 1
            else:
                max_value = f(k - 1, b)[0]
                sol = 0
            memo[k, b] = max_value, sol
            return memo[k, b]

    memo = {}
    opt_val, sol = f(len(s) - 1, b)

    x = [0 for i in range(len(s))]
    for k in range(len(s) - 1, -1, -1):
        val, sol = memo[k, b]
        if sol == 1:
            x[k] += 1
        b -= s[k] * sol
        if b <= 0:
            break

    return opt_val, x
s = [2, 3, 4, 5]
v = [16, 19, 23, 28]
b = 7
opt_val, x = kpdp(s, v, b)
print("Opt. value=", opt_val)
print("Sol.=", x)
Opt. value= 44
Sol.= [1, 0, 0, 1]

多制約ナップサック問題

多制約($0$-$1$)ナップサック問題は,以下のように定義される.

$n$ 個のアイテムからなる有限集合 $N$,$m$ 本の制約の添え字集合 $M$, 各々のアイテム $j \in N$ の価値 $v_j (\geq 0)$, アイテム $j \in N$ の制約 $i \in M$ に対する重み $a_{ij}(\geq 0)$, および制約 $i \in M$ に対する制約の上限値 $b_i (\geq 0)$ が与えられたとき, 選択したアイテムの重みの合計が各制約 $i \in M$ の上限値 $b_i$ を超えないという条件の下で, 価値の合計を最大にするように $N$ からアイテムを選択する問題.

ナップサック問題は,アイテム $j (\in N)$ をナップサックに詰めるとき $1$, それ以外のとき $0$ になる $0$-$1$ 変数 $x_j$ を使うと,以下のように整数最適化問題として定式化できる. $$ \begin{array}{l l l} maximize & \sum_{j \in N} v_j x_j & \\ s.t. & \sum_{j \in N} a_{ij} x_j \leq b_i & \forall i \in M \\ & x_j \in \{0,1\} & \forall j \in N \end{array} $$

この問題は,制約が $1$本の問題(ナップサック問題)でも$NP$-困難である. ナップサック問題は,分枝限定法や動的最適化で容易に解くことができるが,制約の数が増えた場合には解くことが困難になる. 多くの市販の汎用の(混合)整数最適化ソルバーは,線形最適化問題に対する単体法や内点法と, 最も標準的に用いられる厳密解法である分枝限定法から構成されているが, 中規模の問題例でも求解が困難になることがある. 動的最適化は,与えられた数値データが小さな整数の場合には高速であるが,制約の数が増えたり,数値データがある程度大きな整数や実数であったりすると,求解が困難になる.

試しに,区間 $(0,1]$ の一様乱数 $U(0,1]$ を用いて以下のような(比較的難しいと言われている)問題例を作成してみた. 制約式の係数 $a_{ij}$ を $1- 1000 \log_2 U(0,1]$ とし,右辺定数 $b_i$ を $0.25 \sum_{j} a_{ij}$, 目的関数の係数 $v_j$ を $10 \sum_{i} a_{ij}/m+10 U(0,1]$ とする.

2007年に出版した本のために,そのとき使用していた市販の数理最適化ソルバーで試したことがある. 変数の数 $n=100$,制約の数 $m=5$ の問題例を,求解したところ,$2$ 時間かけても最適解を得ることができず,メモリ上限を超過してしまった. 本書を書くために,最新の混合整数最適化ソルバーGurobiで試したところ,この程度の問題例なら難なく最適解を得ることができた. もちろん,問題例の規模が増大すると厳密解を得ることが難しくなるが,制限時間内に良好な近似解を得るには十分な性能である.

多制約ナップサック問題のベンチマーク問題例は,以下のサイト(OR Library)から入手することができる.

ただし,このベンチマーク問題例は古く,最新の数理最適化ソルバーには簡単すぎる.

a = {}
b, v = [], []
m = 5
n = 100
for i in range(m):
    sumA = 0.0
    for j in range(n):
        a[i, j] = 1.0 - math.log(random.random(), 2)
        sumA += a[i, j]
    b.append(0.25 * sumA)
for j in range(n):
    sumA = 0.0
    for i in range(m):
        sumA += a[i, j]
    v.append(10.0 * sumA / m + 10.0 * random.random())
import coptpy as cp
from coptpy import COPT, quicksum, tuplelist, multidict, tupledict

GRB = COPT

class Model():
    def __init__(self, name=""):
        env = cp.Envr()
        self.ObjVal = None
        self.model = env.createModel(name)
        
    def addVar(self, *args, **kwargs):
        return self.model.addVar(*args, **kwargs)
    
    def addConstr(self, *args, **kwargs):
        return self.model.addConstr(*args, **kwargs)

    def setObjective(self, *args, **kwargs):
        return self.model.setObjective(*args, **kwargs)
    
    def getVars(self, *args, **kwargs):
        return self.model.getVars(*args, **kwargs)
    
    def getConstrs(self, *args, **kwargs):
        return self.model.getConstrs(*args, **kwargs)
    
    def getSOS(self, *args, **kwargs):
        return self.model.SOS(*args, **kwargs)
    
    def setParam(self, *args, **kwargs):
        return self.model.setParam(*args, **kwargs)
    
    def optimize(self):
        ret = self.model.solve()
        self.ObjVal = self.model.objval 
        self.status = self.model.status
        return ret  
J = list(range(n))
I = list(range(m))
model = Model("mkp")
x = {}
for j in J:
    x[j] = model.addVar(vtype="B", name=f"x({j})")
#model.update()

constr = {}
for i in I:
    for j in J:
        constr[i,j] = model.addConstr(quicksum(a[i, j] * x[j] for j in J) <= b[i], f"Capacity({i},{j})")

model.setParam(GRB.Param.TimeLimit, 10.0)

model.setObjective(quicksum(v[j] * x[j] for j in J), GRB.MAXIMIZE)

model.optimize()
Cardinal Optimizer v6.5.4. Build date Jun 14 2023
Copyright Cardinal Operations 2023. All Rights Reserved

Setting parameter 'TimeLimit' to 10
Model fingerprint: 52101d91

Using Cardinal Optimizer v6.5.4 on macOS
Hardware has 8 cores and 16 threads. Using instruction set X86_AVX512 (12)
Maximizing a MIP problem

The original problem has:
    500 rows, 100 columns and 50000 non-zero elements
    100 binaries

Presolving the problem

The presolved problem has:
    5 rows, 100 columns and 500 non-zero elements
    100 binaries

Starting the MIP solver with 16 threads and 32 tasks

     Nodes    Active  LPit/n  IntInf     BestBound  BestSolution    Gap   Time
         0         1      --       0  2.979899e+03            --    Inf  0.01s
H        0         1      --       0  2.979899e+03 -0.000000e+00 100.0%  0.01s
H        0         1      --       0  2.979899e+03  6.320883e+02  78.8%  0.01s
H        0         1      --       0  2.979899e+03  6.810597e+02  77.1%  0.01s
         0         1      --       5  8.370620e+02  6.810597e+02  18.6%  0.03s
H        0         1      --       5  8.370620e+02  7.979486e+02  4.67%  0.03s
H        0         1      --       5  8.370620e+02  8.030718e+02  4.06%  0.05s
H        0         1      --       5  8.370620e+02  8.200083e+02  2.04%  0.05s
         0         1      --       6  8.370206e+02  8.200083e+02  2.03%  0.06s
         0         1      --       7  8.370011e+02  8.200083e+02  2.03%  0.06s
         0         1      --       8  8.369921e+02  8.200083e+02  2.03%  0.06s
         0         1      --       9  8.369860e+02  8.200083e+02  2.03%  0.06s
         0         1      --       8  8.369742e+02  8.200083e+02  2.03%  0.06s
         0         1      --       8  8.369374e+02  8.200083e+02  2.02%  0.07s
         0         1      --       8  8.369236e+02  8.200083e+02  2.02%  0.07s

     Nodes    Active  LPit/n  IntInf     BestBound  BestSolution    Gap   Time
         0         1      --       9  8.369188e+02  8.200083e+02  2.02%  0.07s
         0         1      --       9  8.369182e+02  8.200083e+02  2.02%  0.07s
         0         1      --       8  8.369055e+02  8.200083e+02  2.02%  0.07s
         0         1      --       9  8.369050e+02  8.200083e+02  2.02%  0.08s
         0         1      --       9  8.368894e+02  8.200083e+02  2.02%  0.08s
         0         1      --       9  8.368445e+02  8.200083e+02  2.01%  0.08s
         0         1      --      10  8.368441e+02  8.200083e+02  2.01%  0.08s
         0         1      --      10  8.368417e+02  8.200083e+02  2.01%  0.08s
         0         1      --      11  8.368416e+02  8.200083e+02  2.01%  0.09s
         0         1      --      10  8.368218e+02  8.200083e+02  2.01%  0.09s
         0         1      --      11  8.368028e+02  8.200083e+02  2.01%  0.09s
         0         1      --      12  8.367648e+02  8.200083e+02  2.00%  0.09s
         0         1      --      11  8.367553e+02  8.200083e+02  2.00%  0.09s
H        0         0      --      11  8.367183e+02  8.285295e+02  0.98%  0.11s
         1         2    42.0      11  8.367183e+02  8.285295e+02  0.98%  0.11s

     Nodes    Active  LPit/n  IntInf     BestBound  BestSolution    Gap   Time
         2         2    23.5      11  8.367183e+02  8.285295e+02  0.98%  0.11s
         3         4    17.7       7  8.367183e+02  8.285295e+02  0.98%  0.11s
         4         2    16.0       8  8.365584e+02  8.285295e+02  0.96%  0.11s
         5         4    14.2       5  8.365584e+02  8.285295e+02  0.96%  0.12s
         6         6    13.5       6  8.365584e+02  8.285295e+02  0.96%  0.12s
         7         8    11.9       6  8.365584e+02  8.285295e+02  0.96%  0.12s
         8         2    11.6       5  8.365547e+02  8.285295e+02  0.96%  0.12s
         9         4    10.9       5  8.365547e+02  8.285295e+02  0.96%  0.12s
        10         6    10.1       6  8.365547e+02  8.285295e+02  0.96%  0.12s
H       16         0     7.6       5  8.363972e+02  8.291363e+02  0.87%  0.12s
        20        10     8.1       6  8.363972e+02  8.291363e+02  0.87%  0.12s
        30        30     7.4       5  8.363972e+02  8.291363e+02  0.87%  0.12s
        40        18     6.8       6  8.362911e+02  8.291363e+02  0.86%  0.12s
        50        38     6.4       5  8.362911e+02  8.291363e+02  0.86%  0.12s
        60        58     5.8       5  8.362911e+02  8.291363e+02  0.86%  0.12s

     Nodes    Active  LPit/n  IntInf     BestBound  BestSolution    Gap   Time
        70        46     5.7       5  8.362875e+02  8.291363e+02  0.86%  0.13s
        80        66     5.7       5  8.362875e+02  8.291363e+02  0.86%  0.13s
        90        86     5.5       5  8.362875e+02  8.291363e+02  0.86%  0.13s
       100        74     5.5       5  8.362875e+02  8.291363e+02  0.86%  0.13s
H      107        86     5.5       5  8.362875e+02  8.295325e+02  0.81%  0.13s
       110        94     5.5       5  8.362875e+02  8.295325e+02  0.81%  0.13s
       120       114     5.3       5  8.362875e+02  8.295325e+02  0.81%  0.13s
       130       102     5.2       5  8.362771e+02  8.295325e+02  0.81%  0.13s
       140       121     5.1       5  8.362771e+02  8.295325e+02  0.81%  0.13s
       150       141     5.0       5  8.362771e+02  8.295325e+02  0.81%  0.13s
       160       129     4.9       5  8.362771e+02  8.295325e+02  0.81%  0.14s
       170       149     4.9       5  8.362771e+02  8.295325e+02  0.81%  0.14s
       180       168     4.8       5  8.362771e+02  8.295325e+02  0.81%  0.14s
       190       188     4.7       9  8.362771e+02  8.295325e+02  0.81%  0.14s
       200       176     4.7       5  8.362771e+02  8.295325e+02  0.81%  0.14s

     Nodes    Active  LPit/n  IntInf     BestBound  BestSolution    Gap   Time
       300       280     4.8       7  8.362771e+02  8.295325e+02  0.81%  0.15s
       400       383     4.8       5  8.361551e+02  8.295325e+02  0.79%  0.16s
       500       483     4.6       5  8.360428e+02  8.295325e+02  0.78%  0.17s
       600        52     4.7       5  8.360428e+02  8.295325e+02  0.78%  0.27s
       700       156     4.7       6  8.360428e+02  8.295325e+02  0.78%  0.28s
       800       228     4.7       7  8.360428e+02  8.295325e+02  0.78%  0.29s
       900       331     4.7       5  8.360428e+02  8.295325e+02  0.78%  0.30s
      1000       435     4.7       5  8.360326e+02  8.295325e+02  0.78%  0.31s
      1100       535     4.7       5  8.359628e+02  8.295325e+02  0.77%  0.32s
      1200       637     4.7       5  8.358293e+02  8.295325e+02  0.75%  0.33s
      1300       728     4.7       5  8.357584e+02  8.295325e+02  0.74%  0.34s
      1400       819     4.7       5  8.357518e+02  8.295325e+02  0.74%  0.36s
      1500       916     4.7       5  8.357518e+02  8.295325e+02  0.74%  0.37s
      1600       975     4.7       8  8.356818e+02  8.295325e+02  0.74%  0.39s
      1700      1068     4.6       5  8.356672e+02  8.295325e+02  0.73%  0.40s

     Nodes    Active  LPit/n  IntInf     BestBound  BestSolution    Gap   Time
H     1727      1084     4.6       7  8.356177e+02  8.309271e+02  0.56%  0.40s
      1800      1093     4.6       6  8.355741e+02  8.309271e+02  0.56%  0.41s
H     1817      1125     4.6       7  8.355741e+02  8.321257e+02  0.41%  0.41s
      1900       985     4.5       5  8.354958e+02  8.321257e+02  0.40%  0.42s
      2000      1050     4.5       5  8.354745e+02  8.321257e+02  0.40%  0.43s
      3000      1708     4.1       6  8.352221e+02  8.321257e+02  0.37%  0.53s
      4000      2125     3.8       5  8.349637e+02  8.321257e+02  0.34%  0.60s
      5000       288     3.7       6  8.348858e+02  8.321257e+02  0.33%  0.74s
      6000       979     3.7       5  8.348858e+02  8.321257e+02  0.33%  0.85s
H     6783      1414     3.6       7  8.348858e+02  8.322021e+02  0.32%  0.94s
      7000      1541     3.6       5  8.348858e+02  8.322021e+02  0.32%  0.96s
      8000      1925     3.5       5  8.348858e+02  8.322021e+02  0.32%  1.05s
      9000      2145     3.4       5  8.347601e+02  8.322021e+02  0.31%  1.13s
     10000      2306     3.2       5  8.346454e+02  8.322021e+02  0.29%  1.19s
     11000      2443     3.1       6  8.345439e+02  8.322021e+02  0.28%  1.25s

     Nodes    Active  LPit/n  IntInf     BestBound  BestSolution    Gap   Time
     12000      2489     3.0       5  8.344446e+02  8.322021e+02  0.27%  1.29s
     13000      2482     2.9       4  8.343602e+02  8.322021e+02  0.26%  1.33s
     14000      2455     2.9       6  8.343053e+02  8.322021e+02  0.25%  1.36s
     15000      2350     2.8       6  8.342248e+02  8.322021e+02  0.24%  1.39s
     16000      2208     2.7       5  8.341446e+02  8.322021e+02  0.23%  1.44s
     17000      1982     2.6       5  8.340310e+02  8.322021e+02  0.22%  1.47s
     18000      1721     2.6       5  8.338844e+02  8.322021e+02  0.20%  1.50s
     19000      1344     2.5       5  8.337303e+02  8.322021e+02  0.18%  1.54s
     20000       871     2.4       5  8.335160e+02  8.322021e+02  0.16%  1.56s
     21327         0     2.3       5  8.322021e+02  8.322021e+02  0.00%  1.59s

Best solution   : 832.202085869
Best bound      : 832.202085869
Best gap        : 0.0000%
Solve time      : 1.59
Solve node      : 21327
MIP status      : solved
Solution status : integer optimal (relative gap limit 0.0001)

Violations      :     absolute     relative
  bounds        :            0            0
  rows          :            0            0
  integrality   :            0
if model.status == GRB.OPTIMAL:
    print("Objective value =", model.ObjVal)
    print("Solution:")
    for j in x:
        print(f"x[{j}]={x[j].X}")
Objective value = 832.2020858689266
Solution:
x[0]=1.0
x[1]=0.0
x[2]=0.0
x[3]=0.0
x[4]=0.0
x[5]=0.0
x[6]=1.0
x[7]=1.0
x[8]=0.0
x[9]=0.0
x[10]=0.0
x[11]=0.0
x[12]=0.0
x[13]=1.0
x[14]=1.0
x[15]=0.0
x[16]=1.0
x[17]=0.0
x[18]=1.0
x[19]=0.0
x[20]=0.0
x[21]=0.0
x[22]=0.0
x[23]=0.0
x[24]=0.0
x[25]=0.0
x[26]=0.0
x[27]=0.0
x[28]=0.0
x[29]=0.0
x[30]=1.0
x[31]=1.0
x[32]=0.0
x[33]=0.0
x[34]=1.0
x[35]=0.0
x[36]=1.0
x[37]=0.0
x[38]=1.0
x[39]=0.0
x[40]=0.0
x[41]=0.0
x[42]=0.0
x[43]=0.0
x[44]=0.0
x[45]=0.0
x[46]=1.0
x[47]=0.0
x[48]=1.0
x[49]=0.0
x[50]=0.0
x[51]=0.0
x[52]=0.0
x[53]=0.0
x[54]=0.0
x[55]=0.0
x[56]=0.0
x[57]=0.0
x[58]=0.0
x[59]=0.0
x[60]=0.0
x[61]=1.0
x[62]=1.0
x[63]=0.0
x[64]=0.0
x[65]=1.0
x[66]=0.0
x[67]=0.0
x[68]=1.0
x[69]=1.0
x[70]=0.0
x[71]=0.0
x[72]=0.0
x[73]=1.0
x[74]=0.0
x[75]=0.0
x[76]=0.0
x[77]=0.0
x[78]=0.0
x[79]=0.0
x[80]=0.0
x[81]=1.0
x[82]=0.0
x[83]=1.0
x[84]=0.0
x[85]=0.0
x[86]=1.0
x[87]=1.0
x[88]=0.0
x[89]=0.0
x[90]=0.0
x[91]=1.0
x[92]=0.0
x[93]=0.0
x[94]=1.0
x[95]=0.0
x[96]=1.0
x[97]=0.0
x[98]=1.0
x[99]=0.0