1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GTAでTSPをば

Posted at

ぼくのぬまち 出張版のGTALib で TSP にインスパイアされて既存の generator で片付けるにはどうするかを考えた結果。

辺をn本並べるのを全通り生成して、パスとしてつながっているものだけ残して、更に全ての頂点に訪れているものだけ残して、最後に大小関係を逆転して最大和解を求める。一応、愚直に O(n^n) なものを O(n^4 2^n) に落とせてはいる。

TSPCons.hs
import GTA.Core;
import GTA.Data.ConsList;
import qualified Data.IntSet as IntSet
import System.Environment

-- checks whether a given list of edges is a path or not
isPath = ok <.> foldr' f e where
    ok = maybe False (\_ -> True)
    e = Just Nothing
    f _ Nothing = Nothing
    f ((v,_),_) (Just Nothing) = Just $ Just v
    f ((v,u),_) (Just (Just w)) | u == w = Just $ Just v
                                | True   =  Nothing
-- checks whether a given list of edges is a simple cycle of length n or not
spans n = ok <.> foldr' f e where
    e = IntSet.empty
    f ((v,_), _) x = IntSet.insert v x
    ok x = IntSet.size x == n

-- generates a list of edges from 1 to 1 including non-simple cycles.
genEdgeList n = assignsBy (edges n) [1..n]
edges n m | m == 1 = [(1, k) | k <- [2..n]]
          | m == n = [(k, 1) | k <- [2..n]]
          | True   = [(k, l) | k <- [2..n], l <- [2..n], not (k==l)]

-- TSP solver
tsp dist n = genEdgeList n
             `filterBy` isPath
             `filterBy` spans n
             `aggregateBy` maxsumsolutionWith (revOrd . dist . fst)

-- The answer is 1 -> 2 -> ... -> n -> 1 (and its reverse)
lineardist (m, n) | m == n - 1 = 1
                  | n == m - 1 = 1
                  | m < n = n - m + 1
                  | True  = m - n + 1

main = do a <- getArgs
          let n | length a > 0 = read $ head a
                | True         = 11
          putStrLn $ "n = " ++ show n
          print $ tsp lineardist n

{-
ghc TSPCons.hs -o TSPCons -O2 -rtsopts

time ./TSPCons 11

-}

{- 
-----------
Discussion
-----------

The size of the range of foldr of isPath is n+2.
The size of the range of foldr of spans n is 2^n

Therefore, the size of a table is O(n2^n) .

The number of signs assigned to an element by assignsBy is O(n^2).

The assignsBy updates the table O(n) times.

In total, O(n^4 2^n) algorithm.

This is worse than the well-known DP of TSP by a factor of O(n^2) (perhaps). The reason is that we generate a list of edges so that we can compute the minimum sum by the given aggregator. We might be able to define a new aggregator to avoid this factor. 

-}

ついでに JoinList 版。テーブルマージの計算がテーブルサイズの2乗で効いてくるので O(n^5 4^n) とか。

TSP.hs
-- GTALib >= 0.0.6

import GTA.Core;
import GTA.Data.JoinList;
import qualified Data.IntSet as IntSet
import System.Environment


-- checks whether a given list of edges is a path or not
isPath = ok <.> homJ' times single nil where
    ok = maybe False (\_ -> True)
    nil = Just Nothing
    single (x, _) = Just $ Just x
    times Nothing _ = Nothing
    times _ Nothing = Nothing
    times (Just Nothing) x = x
    times x (Just Nothing) = x
    times (Just (Just (u, v))) (Just ( Just (w, z))) 
        = if v == w then Just $ Just (u, z) 
          else Nothing 

-- checks whether a given list of edges is a simple cycle of length n or not
spans n = ok <.> homJ' times single nil where
    ok x = IntSet.size x == n
    nil = IntSet.empty
    single ((v,_), _) = IntSet.singleton v
    times = IntSet.union

-- generates a list of edges from 1 to 1 including non-simple cycles.
genEdgeList n = assignsBy (edges n) [1..n]
edges n m | m == 1 = [(1, k) | k <- [2..n]]
          | m == n = [(k, 1) | k <- [2..n]]
          | True   = [(k, l) | k <- [2..n], l <- [2..n], not (k==l)]

-- TSP solver
tsp dist n = genEdgeList n
             `filterBy` isPath
             `filterBy` spans n
             `aggregateBy` maxsumsolutionWith (revOrd . dist . fst)

-- The answer is 1 -> 2 -> ... -> n -> 1 (and its reverse)
lineardist (m, n) | m == n - 1 = 1
                  | n == m - 1 = 1
                  | m < n = n - m + 1
                  | True  = m - n + 1


-- TSP solver (parallel version)
tspP dist n = assignsByP (edges n) [1..n]
             `filterBy` isPath
             `filterBy` spans n
             `aggregateBy` maxsumsolutionWith (revOrd . dist . fst)

main = do a <- getArgs
          let n | length a > 0 = read $ head a
                | True         = 11
          putStrLn $ "n = " ++ show n
          print $ tsp lineardist n

{-
ghc -threaded -rtsopts TSP.hs -o TSP -O2

time ./TSP 11 +RTS -N1
time ./TSP 11 +RTS -N2

-}

{- 
-----------
Discussion
-----------

The size of the range of foldr of isPath is n^2+2.
The size of the range of foldr of spans n is 2^n

Therefore, the size of a table is O(n^2 2^n) .

In total, O(n^5 4^n) algorithm?

-}

TSP でやったことを少し抽象化すると、permutation を全生成する generator が手に入る。見た目が O(n!) (=O(n^n)) のものを O(n^2 2^n) に落とす程度の能力。mapMap f はバッグに入っているリストに map f する変換操作。

perms :: [a] -> ConsSemiring a s -> s
perms x = assigns (zip [1..n] x) [1..n] `transformBy` mapMap fst `filterBy` spans n `transformBy` mapMap snd
  where n = length x

spans n = ok <.> foldr' f e where
    e = IntSet.empty
    f (v,_) x = IntSet.insert v x
    ok x = IntSet.size x == n
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?