packages feed

toysolver-0.6.0: samples/programs/assign/assign.hs

{-
A program for solving following assignment problems from
<http://people.brunel.ac.uk/~mastjjb/jeb/orlib/assigninfo.html>.

Problem set        Files
100                assign100
200                assign200
300                assign300
400                assign400
500                assign500
600                assign600
700                assign700
800                assign800

Use "-p" option to solve those problem.

Problem set        Files
800                assignp800
1500               assignp1500
3000               assignp3000
5000               assignp5000
-}
module Main where

import Control.Monad
import Data.Attoparsec.ByteString.Char8 hiding (isSpace)
import qualified Data.Attoparsec.ByteString.Lazy as AL
import qualified Data.ByteString.Lazy.Char8 as BL
import Data.Char
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
import Data.List
import qualified Data.Vector.Unboxed as VU
import System.Environment
import ToySolver.Combinatorial.BipartiteMatching

main :: IO ()
main = do
  args <- getArgs
  case args of
    [fname] -> do
      s <- BL.readFile fname
      let (as, bs, w) = parse1 s
          (obj, m, _) = minimumWeightPerfectMatchingComplete as bs w
      putStrLn $ "obj = " ++ show obj
      forM_ (IntMap.toList m) $ \(a,b) -> do
        putStrLn $ unwords $ map show [a,b]
    ["-pp", fname] -> do
      s <- BL.readFile fname
      let (as, bs, w) = parse1 s
          es = [(a, b, w a b) | a <- IntSet.toList as, b <- IntSet.toList bs]
      case minimumWeightPerfectMatching as bs es of
        Nothing ->
          putStrLn $ "infeasible"
        Just (obj, m, _) -> do
          putStrLn $ "obj = " ++ show obj
          forM_ (IntMap.toList m) $ \(a,b) -> do
            putStrLn $ unwords $ map show [a,b]
    ["-p", fname] -> do
      s <- BL.readFile fname
      let (as, bs, es) = parse2 s
      case minimumWeightPerfectMatching as bs es of
        Nothing ->
          putStrLn $ "infeasible"
        Just (obj, m, _) -> do
          putStrLn $ "obj = " ++ show obj
          forM_ (IntMap.toList m) $ \(a,b) -> do
            putStrLn $ unwords $ map show [a,b]

parse1 :: BL.ByteString -> (IntSet, IntSet, Int -> Int -> Int)
parse1 s = (as, bs, w)
  where
    f s =
      case BL.readInt s of
        Nothing -> Nothing
        Just (i,s') -> Just (i, BL.dropWhile isSpace s')
    (n:xs) = unfoldr f (BL.dropWhile isSpace s)
    tbl :: VU.Vector Int
    tbl = VU.fromListN (n*n) xs
    as = IntSet.fromList [0..n-1]
    bs = as
    w a b = tbl VU.! (a*n+b)

parse2 :: BL.ByteString -> (IntSet, IntSet, [(Int,Int,Int)])
parse2 s =
  case AL.eitherResult (AL.parse pfile s) of
    Left s -> error s
    Right x -> x

pfile :: Parser (IntSet, IntSet, [(Int,Int,Int)])
pfile = do
  skipSpace
  n <- decimal <* skipSpace
  let p es =
        mplus
          (do a <- decimal <* skipSpace
              b <- decimal <* skipSpace
              w <- decimal <* skipSpace
              p ((a,b,w) : es))
          (endOfInput *> return es)
  es <- p []
  let as = IntSet.fromList [1..n]
      bs = as
  return (as, bs, es)