{-| Module : MZinHaskell Description : Integration of MiniZinc 2.0 in Haskell Copyright : (c) Some Guy, 2013 Someone Else, 2014 License : BSD3 Maintainer : Klara Marntirosian Stability : experimental This module integrates constraint solving programming through MiniZinc in Haskell. -} module Interfaces.MZinHaskell ( module Interfaces.MZAST, module Interfaces.FZSolutionParser, module Interfaces.MZPrinter, iTestModel, testModel, testModelWithData, writeData ) where import Data.List import System.Process import System.FilePath import Interfaces.MZAuxiliary import Interfaces.MZAST hiding (UserD, PrefBop) import Interfaces.MZPrinter import Interfaces.FZSolutionParser import Text.Parsec.Error -- | Same as `testModel` but accepts one more argument for the data of the model. testModelWithData :: MZModel -- ^ The model -> MZModel -- ^ The data to be used by the model -> FilePath -- ^ Path of the file in which the FlatZinc translation will be printed (without ".fzn" extension) -> Int -- ^ Chosen solver (@1@ for the G12/FD built-in solver or @2@ for choco3) -> Int -- ^ Number of solutions to be returned -> IO (Either ParseError [Solution]) testModelWithData model mdata path solver num = let fdata = [Comment "Model\'s data"] ++ mdata ++ [Empty] in testModel (fdata ++ model) path solver num -- | Same as `testModel`, but interactive. -- -- Interactively runs a constraint model and outputs its solution(s). The -- function first prompts the user for the working directory: the FlatZinc file -- will be created in that directory. Then, for a name for the constraint model: -- the created FlatZinc file will be named after this. Also asks the user to -- choose between supported solvers and the desired number of solutions. Returns -- either a parse error or a list of solutions of the constraint model. The length -- of the list is specified by the number of solutions requested. iTestModel :: MZModel -> IO (Either ParseError [Solution]) iTestModel m = do putStrLn "Enter working directory:" dirpath <- getLine putStr "Enter model\'s name: " name <- getLine putStr "Choose a solver from the list below:\r\n\t1. G12/FD\r\n\t2. choco3\r\n\r\nInteger value associated with the solver: " str_solver <- getLine putStr "Number of solutions to be returned: " str_ns <- getLine let solver = read str_solver ns = read str_ns path = joinPath [dirpath, name] testModel m path solver ns -- | Runs a model and parses its solution(s). testModel :: MZModel -- ^ The model -> FilePath -- ^ The path of the file in which the FlatZinc translation will be printed (without ".fzn" extension) -> Int -- ^ The chosen solver (@1@ for the G12/FD built-in solver or @2@ for choco3) -> Int -- ^ The number of solutions to be returned -> IO (Either ParseError [Solution]) testModel m mpath s n = do configuration <- parseConfig let mz_dir = case minizinc configuration of "" -> addTrailingPathSeparator "." str -> addTrailingPathSeparator str let mfzn = (spaceFix $ mz_dir ++ "mzn2fzn") ++ " -O- - -o " ++ (spaceFix (mpath ++ ".fzn")) let flatzinc = spaceFix $ mz_dir ++ "flatzinc" -- Uncomment line below for debugging only -- writeFile (mpath ++ ".mzn") (Prelude.show $ printModel m) readCreateProcess (shell mfzn) (Prelude.show $ printModel m) res <- case s of 1 -> readCreateProcess (shell $ flatzinc ++ " -a -b fd " ++ mpath ++ ".fzn") "" --1 -> readCreateProcess (shell $ flatzinc ++ " -a -b fd " ++ mpath ++ ".fzn > " ++ mpath ++ ".fzn.results.txt") "" 2 -> let antlr = antlr_path configuration chocoParser = chocoparser configuration chocoSolver = chocosolver configuration in readCreateProcess (shell $ "java -cp ." ++ (intercalate [searchPathSeparator] [chocoSolver, chocoParser, antlr]) ++ " org.chocosolver.parser.flatzinc.ChocoFZN -a " ++ mpath ++ ".fzn") "" --in readCreateProcess (shell $ "java -cp ." ++ (intercalate [searchPathSeparator] [chocoSolver, chocoParser, antlr]) ++ " org.chocosolver.parser.flatzinc.ChocoFZN -a " ++ mpath ++ ".fzn > " ++ mpath ++ ".fzn.results.txt") "" return $ getSolution n res --getSolutionFromFile (mpath ++ ".fzn.results.txt") n -- | Writes the model's data file. The 'MZModel' of the argument must contain -- only `Assignment` items. writeData :: MZModel -> IO () writeData m = do putStrLn "Enter datafile's filepath:" datapath <- getLine writeFile datapath (Prelude.show $ printModel m)