combinatorial-problems 0.0.1 → 0.0.2
raw patch · 16 files changed
+348/−104 lines, 16 filesbinary-addedPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ FileFormat.TSPLIB: instance Show Specification
+ FileFormat.TSPLIB: loadTSPFile :: InternalStorage -> FilePath -> IO TSPProblem
Files
- CombinatorialOptimisation/SAT.hi binary
- CombinatorialOptimisation/SAT.o binary
- CombinatorialOptimisation/TSP.hi binary
- CombinatorialOptimisation/TSP.hs +3/−3
- CombinatorialOptimisation/TSP.hs~ +6/−6
- CombinatorialOptimisation/TSP.o binary
- FileFormat/SATLIB.hi binary
- FileFormat/SATLIB.o binary
- FileFormat/TSPLIB.hi binary
- FileFormat/TSPLIB.hs +140/−40
- FileFormat/TSPLIB.hs~ +139/−40
- FileFormat/TSPLIB.o binary
- Test.hs~ +53/−9
- combinatorial-problems.cabal +4/−3
- combinatorial-problems.cabal~ +3/−3
- meep~ too large to diff
+ CombinatorialOptimisation/SAT.hi view
binary file changed (absent → 3172 bytes)
+ CombinatorialOptimisation/SAT.o view
binary file changed (absent → 89920 bytes)
+ CombinatorialOptimisation/TSP.hi view
binary file changed (absent → 3608 bytes)
CombinatorialOptimisation/TSP.hs view
@@ -209,7 +209,7 @@ matrix = M.fromList $ zip cityCoords (randomRs distanceLimits g) -- p' = (\x y->M.findWithDefault 0 (x,y) matrix) explicit = A.listArray (0,numCities*numCities-1) [M.findWithDefault 0 (a,b) matrix | a<-cities,b<-cities]- in TSPProblem 0 M.empty (\x y->explicit A.! (x * numCities + y)) numCities M.empty M.empty+ in TSPProblem 0 M.empty (\x y->explicit A.! (y * numCities + x)) numCities M.empty M.empty -- TSPProblem 0 M.empty p numCities M.empty M.empty {- | Construct a TSPProblem instance for a Symmetric TSP. That is, the distance@@ -229,7 +229,7 @@ matrix = foldl f M.empty (zip cityCoords (randomRs distanceLimits g)) explicit = A.listArray (0,numCities*numCities-1) [M.findWithDefault 0 (a,b) matrix | a<-cities,b<-cities] triangular = A.listArray (0,sum [0..numCities]) [M.findWithDefault 0 (a,b) matrix | a<-cities,b<-[0..a]]- p = if storageType == ExplicitMatrix then (\x y->explicit A.! (x * numCities + y))+ p = if storageType == ExplicitMatrix then (\x y->explicit A.! (y * numCities + x)) else (\x y->let x' = min x y; y' = max x y in triangular A.! (div (y'*y'+y') 2 + x')) in TSPProblem 0 M.empty p numCities M.empty M.empty @@ -250,7 +250,7 @@ triangular = A.listArray (0,sum [0..numCities]) [euclidianDistance (posArr A.! a) (posArr A.! b) | a<-cities,b<-[0..a]] p = case storageType of- ExplicitMatrix -> \x y->explicit A.! (x * numCities + y)+ ExplicitMatrix -> \x y->explicit A.! (y * numCities + x) TriangularMatrix -> (\x y->let x' = min x y; y' = max x y in triangular A.! (div (y'*y'+y') 2 + x')) Recomputation -> \a b->if a == b then 0 else euclidianDistance (posArr A.! a) (posArr A.! b) in TSPProblem 0 M.empty p numCities M.empty M.empty
CombinatorialOptimisation/TSP.hs~ view
@@ -8,7 +8,7 @@ -- Stability : provisional -- Portability : portable -- --- A library for the representation and manipulation of traveling salesperson+-- A library for the representation and manipulation of travelling salesperson -- problems. -- The approach taken is the creation of a complex data structure called -- TSPProblem which contains both the problem, the current solution and @@ -18,12 +18,12 @@ -- sequence. This is to facilitate changing the route quickly, and -- avoid searching for data in lists. ----- The data structure also contains two additonal fields, the +-- The data structure also contains two additional fields, the -- @routeElementToIndex@ and @indexToRouteElement@ components. -- These exist to allow manipulation either by the vertex number -- or the position in the current solution. -- Solutions are hamiltonian cycles.--- For ease of reasoning it is recomended that users do not +-- For ease of reasoning it is recommended that users do not -- attempt to move vertex 0, or index 0, so that solutions -- are cycles from 0 to 0. I may change this in the future to -- lock this down a bit. In the meantime, there is no@@ -100,7 +100,7 @@ rm = snd . ((M.!) (routeMap t)) r = 0:(takeWhile (\x->x/=0) $ iterate rm (rm 0))++[0] -{- | Converts the lookup table of a problem into a comma and newline deliminated+{- | Converts the lookup table of a problem into a comma and newline delimited string. This should facilitate copying into spreadsheets for checking the problem being used and validating solutions by hand. -} @@ -209,7 +209,7 @@ matrix = M.fromList $ zip cityCoords (randomRs distanceLimits g) -- p' = (\x y->M.findWithDefault 0 (x,y) matrix) explicit = A.listArray (0,numCities*numCities-1) [M.findWithDefault 0 (a,b) matrix | a<-cities,b<-cities]- in TSPProblem 0 M.empty (\x y->explicit A.! (x * numCities + y)) numCities M.empty M.empty+ in TSPProblem 0 M.empty (\x y->explicit A.! (y * numCities + x)) numCities M.empty M.empty -- TSPProblem 0 M.empty p numCities M.empty M.empty {- | Construct a TSPProblem instance for a Symmetric TSP. That is, the distance@@ -229,7 +229,7 @@ matrix = foldl f M.empty (zip cityCoords (randomRs distanceLimits g)) explicit = A.listArray (0,numCities*numCities-1) [M.findWithDefault 0 (a,b) matrix | a<-cities,b<-cities] triangular = A.listArray (0,sum [0..numCities]) [M.findWithDefault 0 (a,b) matrix | a<-cities,b<-[0..a]]- p = if storageType == ExplicitMatrix then (\x y->explicit A.! (x * numCities + y))+ p = if storageType == ExplicitMatrix then (\x y->explicit A.! (y * numCities + x)) else (\x y->let x' = min x y; y' = max x y in triangular A.! (div (y'*y'+y') 2 + x')) in TSPProblem 0 M.empty p numCities M.empty M.empty
+ CombinatorialOptimisation/TSP.o view
binary file changed (absent → 118232 bytes)
+ FileFormat/SATLIB.hi view
binary file changed (absent → 1782 bytes)
+ FileFormat/SATLIB.o view
binary file changed (absent → 51112 bytes)
+ FileFormat/TSPLIB.hi view
binary file changed (absent → 2107 bytes)
FileFormat/TSPLIB.hs view
@@ -1,22 +1,58 @@+-----------------------------------------------------------------------------+-- |+-- Module : FileFormat.TSPLIB+-- Copyright : (c) Richard Senington 2011+-- License : GPL-style+-- +-- Maintainer : Richard Senington <sc06r2s@leeds.ac.uk>+-- Stability : provisional+-- Portability : portable+-- +-- Partial loading routines for the TSPLIB file format.+-- The format itself has a large number of variations, +-- and this has only been designed to load the @tsp@ and +-- @atsp@ variants. It has been tried on all the files+-- from the repository in these classes and it parses+-- them at least. +--+-- Relies upon the @CombinatorialOptimisation.TSP@ library.+--+-- Currently this does not use the Haskell parsing +-- libraries, nor ByteString, just some custom built+-- routines.+----------------------------------------------------------------------------- + module FileFormat.TSPLIB( loadTSPFile )where --- only supports a subset of the TSPLIB format--- not using real parsing libraries. This is probably a mistake.--- also, still not using ByteString, also a misake.- import CombinatorialOptimisation.TSP----- load save of TSPLIB -- can only resave explicit data, could be cripling for big--- data sets+import Data.Maybe+import qualified Data.Map as M+import qualified Data.Array as A+import Data.List +{- | Simple 2d Euclidian. -} --- for those files where the co-ordinates of nodes are given euclidianDistance :: (Float,Float)->(Float,Float)->Float euclidianDistance (a,b) (c,d) = sqrt ((a-c)*(a-c)+(b-d)*(b-d)) +{- | Always rounded up Euclidian. -}++euclidianDistanceCeil :: (Float,Float)->(Float,Float)->Float+euclidianDistanceCeil a b = fromIntegral . ceiling $ euclidianDistance a b++{- | For only two types of file. Basically a form of rounded Euclidian. -}++pseudoEuclideanDistance :: (Float,Float)->(Float,Float)->Float+pseudoEuclideanDistance (a,b) (c,d) = let e = sqrt (((a-c)*(a-c)+(b-d)*(b-d)) /10 )+ f = fromIntegral (floor e)+ in if f<e then f+1 else f++{- | Distance between two points on the Earth's surface. This is based upon code that + another developer wrote, based on the code proposed by TSPLIB itself. I am + not sure if this is for an earth shape, or just a sphere. I suspect earth shape. -}+ geoDistance :: (Float,Float)->(Float,Float)->Float geoDistance (x1,y1) (x2,y2) = encodeFloat (floor dij) 0 where@@ -33,27 +69,22 @@ degConvert m = let deg = encodeFloat (floor m) 0 miN = m - deg in 3.141592 * (deg + (5.0 * miN/3.0))/180.0-{--readSpecification :: String->([(String,String)],String)-readSpecification s | name -> print?- | type -> TSP or ATSP only- | comment -> throw or print- | dimension Int- | capacity, not interested- | edge-weight-type -> Lots- | edge-weight-format- | edge-data-format- | node-coord-type- | display-data-type- | eof: end do not expect --}+{- | A data type for representing bits of the specification section of a file.+ Assumed to be used later as a list of Specifications. -} data Specification = IGNORE String | USEFUL String String | ENDSPEC String | FAIL String deriving Show +{- | Test for filtering specification lines, so we only get data we might want to use. Could be+ got rid of as most of the time I do dictionary lookups on the output of the specification+ reading routines. -}+ isUsefulSpec (USEFUL _ _) = True isUsefulSpec _ = False +{- | Helper routine for @readSpecification@. Reads a single line (assumes + that input is already line by line). -}+ readSpecificationLine :: String->Specification readSpecificationLine s | likeString "NAME" s = IGNORE s@@ -64,12 +95,15 @@ | likeString "DIMENSION" s = USEFUL "Dimension" (trim s) | likeString "DISPLAY_DATA_TYPE" s = IGNORE s | likeString "EDGE_WEIGHT_TYPE" s = USEFUL "EdgeWeightType" (trim s)+ | likeString "EDGE_WEIGHT_FORMAT" s = USEFUL "EdgeWeightFormat" (trim s) | otherwise = FAIL $ "unrecognised field in specification : "++s where likeString q s = take (length q) s == q trim s = let s' = (dropWhile (==' ')) . (drop 1) . (dropWhile (/=':')) $ s in reverse . (dropWhile (==' ')) . reverse $ s' +{- | Helper routine for @loadTSPFile@. Reads the specification section of a file. -}+ readSpecification :: [String]->([Specification],[String]) readSpecification [] = ([FAIL "seem to have run out of data, without ending the specification phase"],[]) readSpecification (s:ss) = let p = readSpecificationLine s@@ -80,25 +114,91 @@ FAIL _ -> (p:rs,es) USEFUL _ _ -> (p:rs,es) -loadTSPFile :: String->IO () -- TSPProblem-loadTSPFile fName = do rawContents<-readFile fName- let (spec,remainder) = readSpecification $ lines rawContents- mapM_ print spec- print ""- mapM_ print $ filter isUsefulSpec spec+{- | Loads a TSPLIB style file. The first parameter is the internal + storage type from @CombinatorialProblems.TSP@. It allows for + full matrix, triangular matrix and full recalculation. If the + requested internal storage cannot be used with the file, this + will throw an error (e.g. recomputation where you are given a + full matrix in the file). -{- -readEdgeWeightSection+ The second parameter is the file path. -} -FULL_MATRIX +loadTSPFile :: InternalStorage->FilePath->IO TSPProblem+loadTSPFile storageType fName + = do rawContents<-readFile fName+ let (spec,remainder) = readSpecification $ lines rawContents+ + -- mapM_ print spec+ -- print ""+ + let specList = map (\(USEFUL a b)->(a,b)) . filter isUsefulSpec $ spec+ -- print specList+ let dataPart = fromJust $ lookup "DATA PART TYPE" specList+ let numNodes = read $ fromJust $ lookup "Dimension" specList+ case dataPart of + "NODE COORD" -> return $ loadFromNodePositions storageType numNodes specList (takeWhile (/="EOF") remainder)+ "EDGE WEIGHT" -> return $ loadFromMatrix storageType numNodes specList (takeWhile (/="EOF") remainder)+ _ -> error "Unsupported data section" -readEdgeWeightSection :: Num a=>String->Int->String->IO (Int->Int->Float)-readEdgeWeightSection ty dim inputData - = do +{- | Helper routine for @loadTSPFile@. This assumes the input is just points and the + distances must be calculated. -} -readNodeCoordSection :: Num a=>String->Int->String->IO (Int->Int->Float)-readNodeCoordSection dim inputData - = do - +loadFromNodePositions :: InternalStorage->Int->[(String,String)]->[String]->TSPProblem+loadFromNodePositions storageType numCities spec d + = let d' = map ((\[a,b]->(a,b)) . (map readF) . (drop 1) . words) d+ posArr = A.listArray (0 , numCities-1) d' --}+ cities = [0 ..(numCities-1)]+ + explicit = A.listArray (0,numCities*numCities-1) [distFunc (posArr A.! a) (posArr A.! b) | a<-cities,b<-cities]+ triangular = A.listArray (0,sum [0..numCities]) [distFunc (posArr A.! a) (posArr A.! b) | a<-cities,b<-[0..a]]+ + p = case storageType of+ ExplicitMatrix -> \x y->explicit A.! (x * numCities + y)+ TriangularMatrix -> (\x y->let x' = min x y; y' = max x y in triangular A.! (div (y'*y'+y') 2 + x'))+ Recomputation -> \a b->distFunc (posArr A.! a) (posArr A.! b)+ in TSPProblem 0 M.empty p numCities M.empty M.empty+ where+ readF = read :: (String->Float)+ distanceFunctionSpec = fromJust $ lookup "EdgeWeightType" spec+ distFunc = case distanceFunctionSpec of+ "GEO" -> geoDistance+ "EUC_2D" -> euclidianDistance+ "ATT" -> pseudoEuclideanDistance+ "CEIL_2D"-> euclidianDistanceCeil+ _ -> error $ "unsupported distance function : "++distanceFunctionSpec+ +{- | Helper routine for @loadTSPFile@. This assumes the input data is a matrix of some form, + and loads it. -}++loadFromMatrix :: InternalStorage->Int->[(String,String)]->[String]->TSPProblem+loadFromMatrix Recomputation _ _ _ = error "Cannot load matrix and store in recomputation form"+loadFromMatrix storageType numCities spec d+ | distanceFunctionSpec /= "EXPLICIT" = error "loading from non explicit matrix? (does not make sense)"+ | storageType == TriangularMatrix = TSPProblem 0 M.empty (\x y->let x' = min x y; y' = max x y in triangularArray A.! (div (y'*y'+y') 2 + x')) numCities M.empty M.empty+ | storageType == ExplicitMatrix = TSPProblem 0 M.empty (\x y->explicitArray A.! (y * numCities + x)) numCities M.empty M.empty+ where+ readF = read :: (String->Float)+ distanceFunctionSpec = fromJust $ lookup "EdgeWeightType" spec+ inputNumberSequence = concatMap ((map readF) . words) d -- not entirely trusting line breaks in file format, so turning into list of numbers, and putting in coords later+ cities = [0 ..(numCities-1)]++ blankMatrix = foldl' (\m d->M.insert (d,d) 0 m) M.empty cities+ fillPair m ((a,b),c) = M.insert (b,a) c $ (M.insert (a,b) c m)+ makeFromTri = foldl' fillPair blankMatrix++ loadedMap = case fromJust $ lookup "EdgeWeightFormat" spec of+ "FULL_MATRIX" -> foldl' (\m (d,c)->M.insert d c m) M.empty (zip [(a,b) | a<-cities,b<-cities] inputNumberSequence)+ "UPPER_ROW" -> makeFromTri $ zip [(a,b) | a<-cities,b<-[a..(numCities - 1)],a/=b] inputNumberSequence+ "LOWER_ROW" -> makeFromTri $ zip [(a,b) | a<-cities,b<-[0..a],a/=b] inputNumberSequence+ "UPPER_DIAG_ROW" -> makeFromTri $ zip [(a,b) | a<-cities,b<-[a..(numCities - 1)]] inputNumberSequence+ "LOWER_DIAG_ROW" -> makeFromTri $ zip [(a,b) | a<-cities,b<-[0..a]] inputNumberSequence++ "UPPER_COL" -> makeFromTri $ zip [(b,a) | a<-cities,b<-[a..(numCities - 1)],a/=b] inputNumberSequence+ "LOWER_COL" -> makeFromTri $ zip [(b,a) | a<-cities,b<-[0..a],a/=b] inputNumberSequence+ "UPPER_DIAG_COL" -> makeFromTri $ zip [(b,a) | a<-cities,b<-[a..(numCities - 1)]] inputNumberSequence+ "LOWER_DIAG_COL" -> makeFromTri $ zip [(b,a) | a<-cities,b<-[0..a]] inputNumberSequence+ + explicitArray = A.listArray (0,numCities*numCities-1) [loadedMap M.! (a,b) | a<-cities,b<-cities]+ triangularArray = A.listArray (0,sum [0..numCities]) [loadedMap M.! (a,b) | a<-cities,b<-[0..a]]+
FileFormat/TSPLIB.hs~ view
@@ -1,22 +1,58 @@+-----------------------------------------------------------------------------+-- |+-- Module : FileFormat.TSPLIB+-- Copyright : (c) Richard Senington 2011+-- License : GPL-style+-- +-- Maintainer : Richard Senington <sc06r2s@leeds.ac.uk>+-- Stability : provisional+-- Portability : portable+-- +-- Partial loading routines for the TSPLIB file format.+-- The format itself has a large number of variations, +-- and this has only been designed to load the @tsp@ and +-- @atsp@ variants. It has been tried on all the files+-- from the repository in these classes and it parses+-- them at least. +--+-- Relies upon the @CombinatorialOptimisation.TSP@ library.+--+-- Currently this does not use the Haskell parsing +-- libraries, nor ByteString, just some custom built+-- routines.+----------------------------------------------------------------------------- + module FileFormat.TSPLIB( loadTSPFile )where --- only supports a subset of the TSPLIB format--- not using real parsing libraries. This is probably a mistake.--- also, still not using ByteString, also a misake.- import CombinatorialOptimisation.TSP----- load save of TSPLIB -- can only resave explicit data, could be cripling for big--- data sets+import Data.Maybe+import qualified Data.Map as M+import qualified Data.Array as A+import Data.List +{- | Simple 2d Euclidian. -} --- for those files where the co-ordinates of nodes are given euclidianDistance :: (Float,Float)->(Float,Float)->Float euclidianDistance (a,b) (c,d) = sqrt ((a-c)*(a-c)+(b-d)*(b-d)) +{- | Always rounded up euclidian. -}++euclidianDistanceCeil :: (Float,Float)->(Float,Float)->Float+euclidianDistanceCeil a b = fromIntegral . ceiling $ euclidianDistance a b++{- | For only two types of file. Basically a form of rounded euclidian. -}++pseudoEuclideanDistance :: (Float,Float)->(Float,Float)->Float+pseudoEuclideanDistance (a,b) (c,d) = let e = sqrt (((a-c)*(a-c)+(b-d)*(b-d)) /10 )+ f = fromIntegral (floor e)+ in if f<e then f+1 else f++{- | Distance between two points on the earths surface. This is based upon code that + another developer wrote, based on the code proposed by TSPLIB itself. I am + not sure if this is for an earth shape, or just a sphere. I suspect earth shape. -}+ geoDistance :: (Float,Float)->(Float,Float)->Float geoDistance (x1,y1) (x2,y2) = encodeFloat (floor dij) 0 where@@ -33,27 +69,22 @@ degConvert m = let deg = encodeFloat (floor m) 0 miN = m - deg in 3.141592 * (deg + (5.0 * miN/3.0))/180.0-{--readSpecification :: String->([(String,String)],String)-readSpecification s | name -> print?- | type -> TSP or ATSP only- | comment -> throw or print- | dimension Int- | capacity, not interested- | edge-weight-type -> Lots- | edge-weight-format- | edge-data-format- | node-coord-type- | display-data-type- | eof: end do not expect --}+{- | A data type for representing bits of the specification section of a file.+ Assumed to be used later as a list of Specifications. -} data Specification = IGNORE String | USEFUL String String | ENDSPEC String | FAIL String deriving Show +{- | Test for filtering specification lines, so we only get data we might want to use. Could be+ got rid of as most of the time I do dictionary lookups on the output of the specification+ reading routines. -}+ isUsefulSpec (USEFUL _ _) = True isUsefulSpec _ = False +{- | Helper routine for @readSpecification@. Reads a single line (assumes + that input is already line by line). -}+ readSpecificationLine :: String->Specification readSpecificationLine s | likeString "NAME" s = IGNORE s@@ -64,12 +95,15 @@ | likeString "DIMENSION" s = USEFUL "Dimension" (trim s) | likeString "DISPLAY_DATA_TYPE" s = IGNORE s | likeString "EDGE_WEIGHT_TYPE" s = USEFUL "EdgeWeightType" (trim s)+ | likeString "EDGE_WEIGHT_FORMAT" s = USEFUL "EdgeWeightFormat" (trim s) | otherwise = FAIL $ "unrecognised field in specification : "++s where likeString q s = take (length q) s == q trim s = let s' = (dropWhile (==' ')) . (drop 1) . (dropWhile (/=':')) $ s in reverse . (dropWhile (==' ')) . reverse $ s' +{- | Helper routine for @loadTSPFile@. Reads the specification section of a file. -}+ readSpecification :: [String]->([Specification],[String]) readSpecification [] = ([FAIL "seem to have run out of data, without ending the specification phase"],[]) readSpecification (s:ss) = let p = readSpecificationLine s@@ -80,26 +114,91 @@ FAIL _ -> (p:rs,es) USEFUL _ _ -> (p:rs,es) +{- | Loads a TSPLIB style file. The first parameter is the internal + storage type from @CombinatorialProblems.TSP@. It allows for + full matrix, triangular matrix and full recalculation. If the + requested internal storage cannot be used with the file, this + will throw an error (e.g. recomputation where you are given a + full matrix in the file). -loadTSPFile :: String->IO () -- TSPProblem-loadTSPFile fName = do rawContents<-readFile fName- let (spec,remainder) = readSpecification $ lines rawContents- mapM_ print spec- print ""- mapM_ print $ filter isUsefulSpec spec+ The second parameter is the file path. -} -{- -readEdgeWeightSection+loadTSPFile :: InternalStorage->FilePath->IO TSPProblem+loadTSPFile storageType fName + = do rawContents<-readFile fName+ let (spec,remainder) = readSpecification $ lines rawContents+ + -- mapM_ print spec+ -- print ""+ + let specList = map (\(USEFUL a b)->(a,b)) . filter isUsefulSpec $ spec+ -- print specList+ let dataPart = fromJust $ lookup "DATA PART TYPE" specList+ let numNodes = read $ fromJust $ lookup "Dimension" specList+ case dataPart of + "NODE COORD" -> return $ loadFromNodePositions storageType numNodes specList (takeWhile (/="EOF") remainder)+ "EDGE WEIGHT" -> return $ loadFromMatrix storageType numNodes specList (takeWhile (/="EOF") remainder)+ _ -> error "Unsupported data section" -FULL_MATRIX +{- | Helper routine for @loadTSPFile@. This assumes the input is just points and the + distances must be calculated. -} -readEdgeWeightSection :: Num a=>String->Int->String->IO (Int->Int->Float)-readEdgeWeightSection ty dim inputData - = do +loadFromNodePositions :: InternalStorage->Int->[(String,String)]->[String]->TSPProblem+loadFromNodePositions storageType numCities spec d + = let d' = map ((\[a,b]->(a,b)) . (map readF) . (drop 1) . words) d+ posArr = A.listArray (0 , numCities-1) d' -readNodeCoordSection :: Num a=>String->Int->String->IO (Int->Int->Float)-readNodeCoordSection dim inputData - = do - + cities = [0 ..(numCities-1)]+ + explicit = A.listArray (0,numCities*numCities-1) [distFunc (posArr A.! a) (posArr A.! b) | a<-cities,b<-cities]+ triangular = A.listArray (0,sum [0..numCities]) [distFunc (posArr A.! a) (posArr A.! b) | a<-cities,b<-[0..a]]+ + p = case storageType of+ ExplicitMatrix -> \x y->explicit A.! (x * numCities + y)+ TriangularMatrix -> (\x y->let x' = min x y; y' = max x y in triangular A.! (div (y'*y'+y') 2 + x'))+ Recomputation -> \a b->distFunc (posArr A.! a) (posArr A.! b)+ in TSPProblem 0 M.empty p numCities M.empty M.empty+ where+ readF = read :: (String->Float)+ distanceFunctionSpec = fromJust $ lookup "EdgeWeightType" spec+ distFunc = case distanceFunctionSpec of+ "GEO" -> geoDistance+ "EUC_2D" -> euclidianDistance+ "ATT" -> pseudoEuclideanDistance+ "CEIL_2D"-> euclidianDistanceCeil+ _ -> error $ "unsupported distance function : "++distanceFunctionSpec+ +{- | Helper routine for @loadTSPFile@. This assumes the input data is a matrix of some form, + and loads it. -} --}+loadFromMatrix :: InternalStorage->Int->[(String,String)]->[String]->TSPProblem+loadFromMatrix Recomputation _ _ _ = error "Cannot load matrix and store in recomputation form"+loadFromMatrix storageType numCities spec d+ | distanceFunctionSpec /= "EXPLICIT" = error "loading from non explicit matrix? (does not make sense)"+ | storageType == TriangularMatrix = TSPProblem 0 M.empty (\x y->let x' = min x y; y' = max x y in triangularArray A.! (div (y'*y'+y') 2 + x')) numCities M.empty M.empty+ | storageType == ExplicitMatrix = TSPProblem 0 M.empty (\x y->explicitArray A.! (y * numCities + x)) numCities M.empty M.empty+ where+ readF = read :: (String->Float)+ distanceFunctionSpec = fromJust $ lookup "EdgeWeightType" spec+ inputNumberSequence = concatMap ((map readF) . words) d -- not entirely trusting line breaks in file format, so turning into list of numbers, and putting in coords later+ cities = [0 ..(numCities-1)]++ blankMatrix = foldl' (\m d->M.insert (d,d) 0 m) M.empty cities+ fillPair m ((a,b),c) = M.insert (b,a) c $ (M.insert (a,b) c m)+ makeFromTri = foldl' fillPair blankMatrix++ loadedMap = case fromJust $ lookup "EdgeWeightFormat" spec of+ "FULL_MATRIX" -> foldl' (\m (d,c)->M.insert d c m) M.empty (zip [(a,b) | a<-cities,b<-cities] inputNumberSequence)+ "UPPER_ROW" -> makeFromTri $ zip [(a,b) | a<-cities,b<-[a..(numCities - 1)],a/=b] inputNumberSequence+ "LOWER_ROW" -> makeFromTri $ zip [(a,b) | a<-cities,b<-[0..a],a/=b] inputNumberSequence+ "UPPER_DIAG_ROW" -> makeFromTri $ zip [(a,b) | a<-cities,b<-[a..(numCities - 1)]] inputNumberSequence+ "LOWER_DIAG_ROW" -> makeFromTri $ zip [(a,b) | a<-cities,b<-[0..a]] inputNumberSequence++ "UPPER_COL" -> makeFromTri $ zip [(b,a) | a<-cities,b<-[a..(numCities - 1)],a/=b] inputNumberSequence+ "LOWER_COL" -> makeFromTri $ zip [(b,a) | a<-cities,b<-[0..a],a/=b] inputNumberSequence+ "UPPER_DIAG_COL" -> makeFromTri $ zip [(b,a) | a<-cities,b<-[a..(numCities - 1)]] inputNumberSequence+ "LOWER_DIAG_COL" -> makeFromTri $ zip [(b,a) | a<-cities,b<-[0..a]] inputNumberSequence+ + explicitArray = A.listArray (0,numCities*numCities-1) [loadedMap M.! (a,b) | a<-cities,b<-cities]+ triangularArray = A.listArray (0,sum [0..numCities]) [loadedMap M.! (a,b) | a<-cities,b<-[0..a]]+
+ FileFormat/TSPLIB.o view
binary file changed (absent → 156896 bytes)
Test.hs~ view
@@ -6,6 +6,8 @@ import System.Random import qualified Data.Map as M +import System.Directory+ {- main :: IO() main = do s<-loadCNFFile "./CBS_k3_n100_m403_b10_0.cnf"@@ -33,17 +35,16 @@ -} -{- --- checking stability of arrays, rather than map+{- main :: IO()-main = do gen<-newStdGen- let (meep,meep') = makeASymmetricTSPMap (2,5) 50 gen- putStrLn $ showEdgeWeights meep- putStrLn ""- putStrLn $ showEdgeWeights meep'+main = do let gen = mkStdGen 5+ let meep = makeSymmetricTSPMap ExplicitMatrix (2,5) 50 gen+ let meep' = makeSymmetricTSPMap TriangularMatrix (2,5) 50 gen putStrLn $ show $ showEdgeWeights meep == showEdgeWeights meep'+ -} +{- -- checking stability of arrays, rather than map main :: IO() main = do let gen = mkStdGen 5@@ -55,8 +56,51 @@ putStrLn "" putStrLn $ showEdgeWeights meep' putStrLn $ show $ (showEdgeWeights meep == showEdgeWeights meep') && (showEdgeWeights meep == showEdgeWeights meep'')+-} -{- +{- -- checking loading TSPs main :: IO()-main = do loadTSPFile "../exampleProblems/ali535.tsp" -}+main = do b<-loadTSPFile Recomputation "../exampleProblems/ali535.tsp" + c<-loadTSPFile TriangularMatrix "../exampleProblems/ali535.tsp" + d<-loadTSPFile ExplicitMatrix "../exampleProblems/ali535.tsp" + putStrLn $ show $ (showEdgeWeights d == showEdgeWeights c) && (showEdgeWeights d == showEdgeWeights b)+-}++{-+-- still checking the loading of TSPs+main :: IO()+main = do b<-loadTSPFile ExplicitMatrix "../exampleProblems/brazil58.tsp" + putStrLn $ showEdgeWeights b -}++-- brute force loading+main :: IO()+main = do xs<-getDirectoryContents "../exampleProblems" >>= (\x->return (drop 2 x))+ mapM_ (\x->do b<-loadTSPFile ExplicitMatrix ("../exampleProblems/"++x)+ if (numCities b < 1000) then print $ getLastEdge b + else print $ x++" too big for explicit") xs+ main2+ where+ getLastEdge t = let m = numCities t -1 in edgePrices t m m++problemFiles = ["brazil58.tsp","bayg29.tsp","bays29.tsp","brg180.tsp","dantzig42.tsp"]++customFilter :: [String]->IO [String]+customFilter [] = return []+customFilter (x:xs) = do b<-loadTSPFile ExplicitMatrix ("../exampleProblems/"++x)+ if numCities b <1000 then customFilter xs+ else do ps<-customFilter xs+ return (x:ps)++main2 :: IO()+main2 = do xs<-getDirectoryContents "../exampleProblems" >>= (\x->return (drop 2 x)) + xs' <-customFilter xs+ print xs'+ mapM_ (\x->do print x+ b<-loadTSPFile Recomputation ("../exampleProblems/"++x)+ print $ getLastEdge b ) xs' + where+ getLastEdge t = let m = numCities t -1 in edgePrices t m m+ ++
combinatorial-problems.cabal view
@@ -1,5 +1,5 @@ Name: combinatorial-problems-Version: 0.0.1+Version: 0.0.2 Synopsis: A number of data structures to represent and allow the manipulation of standard combinatorial problems, used as test problems in computer science. Description: In computer science there are a number of standard test problems that are used for testing algorithms, especially those related to Artificial Intelligence and Operations Research. Online there are a number @@ -10,7 +10,7 @@ This library seeks to provide implementations of data structures to store these problems, along with functions for manipulating the problems and routines to load problem files from various sources. .- At present it only supports TSP and SAT\/SATLIB (TSPLIB coming soon), however it is hoped that the loading routines + At present it only supports TSP\/TSPLIB and SAT\/SATLIB, however it is hoped that the loading routines can be expanded and the range of problems expanded to cover problems like scheduling and timetabling. The internal data structures make heavy use of the @Data.Map@ library and @Data.Array@. It is not currently using unboxed values. The library does not use the @bytestring@ library for loading and saving data either, @@ -22,13 +22,14 @@ License: GPL license-file: LICENSE Copyright: Copyright (c) 2011 Richard Senington-Homepage: http://www.comp.leeds.ac.uk/sc06r2s/Projects/HaskellLocalSearch+Homepage: http://www.comp.leeds.ac.uk/sc06r2s/Projects/HaskellCombinatorialProblems Maintainer: sc06r2s@leeds.ac.uk Build-Type: Simple Cabal-Version: >= 1.2 library Exposed-Modules: FileFormat.SATLIB+ FileFormat.TSPLIB CombinatorialOptimisation.SAT CombinatorialOptimisation.TSP Build-Depends: base >= 2.0 && <=5,
combinatorial-problems.cabal~ view
@@ -1,5 +1,5 @@ Name: combinatorial-problems-Version: 0.0.1+Version: 0.0.2 Synopsis: A number of data structures to represent and allow the manipulation of standard combinatorial problems, used as test problems in computer science. Description: In computer science there are a number of standard test problems that are used for testing algorithms, especially those related to Artificial Intelligence and Operations Research. Online there are a number @@ -10,7 +10,7 @@ This library seeks to provide implementations of data structures to store these problems, along with functions for manipulating the problems and routines to load problem files from various sources. .- At present it only supports TSP and SAT\/SATLIB (TSPLIB coming soon), however it is hoped that the loading routines + At present it only supports TSP\/TSPLIB and SAT\/SATLIB, however it is hoped that the loading routines can be expanded and the range of problems expanded to cover problems like scheduling and timetabling. The internal data structures make heavy use of the @Data.Map@ library and @Data.Array@. It is not currently using unboxed values. The library does not use the @bytestring@ library for loading and saving data either, @@ -22,7 +22,7 @@ License: GPL license-file: LICENSE Copyright: Copyright (c) 2011 Richard Senington-Homepage: http://www.comp.leeds.ac.uk/sc06r2s/Projects/HaskellLocalSearch+Homepage: http://www.comp.leeds.ac.uk/sc06r2s/Projects/HaskellCombinatorialProblems Maintainer: sc06r2s@leeds.ac.uk Build-Type: Simple Cabal-Version: >= 1.2
+ meep~ view
file too large to diff