{-# OPTIONS_GHC -Wall #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  ToySolver.Converter.PB2LSP
-- Copyright   :  (c) Masahiro Sakai 2013-2014
-- License     :  BSD-style
-- 
-- Maintainer  :  masahiro.sakai@gmail.com
-- Stability   :  experimental
-- Portability :  portable
--
-----------------------------------------------------------------------------
module ToySolver.Converter.PB2LSP
  ( convert
  , convertWBO
  ) where

import Data.List
import qualified ToySolver.Text.PBFile as PBFile

convert :: PBFile.Formula -> ShowS
convert formula =
  showString "function model() {\n" .
  decls .
  constrs .
  obj2 .
  showString "}\n"
  where
    nv = PBFile.pbNumVars formula

    decls = showString $
      "  for [i in 1.." ++ show nv ++ "] x[i] <- bool();\n"

    constrs = foldr (.) id
      [ showString "  constraint " .
        showString (showConstr c) .
        showString ";\n"
      | c <- PBFile.pbConstraints formula
      ]

    obj2 =
      case PBFile.pbObjectiveFunction formula of
        Just obj' -> showString "  minimize " . showString (showSum obj') . showString ";\n"
        Nothing -> id

convertWBO :: PBFile.SoftFormula -> ShowS
convertWBO softFormula =
  showString "function model() {\n" .
  decls .
  constrs .
  costDef .
  topConstr .
  showString "  minimize cost;\n" .
  showString "}\n"
  where
    nv = PBFile.wboNumVars softFormula

    decls = showString $
      "  for [i in 1.." ++ show nv ++ "] x[i] <- bool();\n"

    constrs = foldr (.) id
      [ showString "  constraint " .
        showString (showConstr c) .
        showString ";\n"
      | (Nothing, c) <- PBFile.wboConstraints softFormula
      ]

    costDef = showString "  cost <- sum(\n" . s . showString ");\n"
      where
        s = foldr (.) id . intersperse (showString ",\n") . map showString $ xs
        xs = ["    " ++ show w ++ "*!(" ++ showConstr c ++ ")" | (Just w, c) <- PBFile.wboConstraints softFormula]

    topConstr =
      case PBFile.wboTopCost softFormula of
        Nothing -> id
        Just t -> showString $ "  constraint cost <= " ++ show t ++ ";\n"

showConstr :: PBFile.Constraint -> String
showConstr (lhs, PBFile.Ge, 1) | and [c==1 | (c,_) <- lhs] =
  "or(" ++ intercalate "," (map (f . snd) lhs) ++ ")"
  where
    f [l] = showLit l
    f ls  = "and(" ++ intercalate "," (map showLit ls) ++ ")"
showConstr (lhs, op, rhs) = showSum lhs  ++ op2 ++ show rhs
  where
    op2 = case op of
            PBFile.Ge -> " >= "
            PBFile.Eq -> " == "

sum' :: [String] -> String
sum' xs = "sum(" ++ intercalate ", " xs ++ ")"

showSum :: PBFile.Sum -> String
showSum = sum' . map showTerm

showTerm :: PBFile.WeightedTerm -> String
showTerm (n,ls) = intercalate "*" $ [show n | n /= 1] ++ [showLit l | l<-ls]

showLit :: PBFile.Lit -> String
showLit l =
  if l < 0
  then "!x[" ++ show (abs l) ++ "]"
  else "x[" ++ show l ++ "]"