module Control.CP.SearchSpec.Language where import Text.PrettyPrint import Data.Monoid import Data.Int spacetype = "MCPProgram" instance Monoid Statement where mempty = Skip mappend = (>>>) class Pretty x where pretty :: x -> Doc data Struct = Struct String [(Type,String)] deriving (Show, Eq) instance Pretty Struct where pretty (Struct name fields) = text "struct" <+> text name <+> text "{" $+$ nest 2 (vcat [pretty ty <+> text f <> text ";" | (ty,f) <- fields]) $+$ text "};" data Type = Pointer Type | SpaceType | Int | Bool | Union [(Type,String)] | SType Struct | THook String deriving (Show, Eq) data Value = IVal Int32 | BVal Bool | RootSpace | Minus Value Value | Plus Value Value | Div Value Value | Mod Value Value | Abs Value | Var String | Clone Value | Field String String | Field' Value String | PField Value String | Lt Value Value | Gq Value Value | Gt Value Value | Eq Value Value | BaseContinue | And Value Value | Or Value Value | Not Value | VHook String | Max Value Value | CVar String Value Value | XVar String Value String | MinDom Value | MaxDom Value | SizeDom Value | Degree Value | WDegree Value | UbRegret Value | LbRegret Value | Median Value | Random | Null | New Struct | Base | Cond Value Value Value | Assigned Value deriving (Show, Eq) instance Num Value where (-) = Minus fromInteger = IVal . fromInteger (+) = Plus (*) = undefined abs = Abs signum = undefined true = BVal True false = BVal False (&&&) = And (|||) = Or (@>) = Gt (@>=) = Gq (@==) = Eq (@->) = Field' (@=>) = PField (@<) = Lt lex cmps l1 l2 = foldr (\(x,y,cmp) r -> (x `cmp` y) ||| ((x @== y) &&& r)) false (zip3 l1 l2 cmps) simplValue :: Value -> Value simplValue (Cond c t e) = let c' = simplValue c t' = simplValue t e' = simplValue e in case (c',t',e') of (BVal True, _, _) -> t' (BVal False, _, _) -> e' _ | t' == e' -> t' _ -> Cond c' t' e' simplValue (Minus (IVal x) (IVal y)) = IVal (x - y) simplValue (Lt x y) = Lt (simplValue x) (simplValue y) simplValue (Gq x y) = Gq (simplValue x) (simplValue y) simplValue (And x y) = let x' = simplValue x y' = simplValue y in case (x',y') of (x, (BVal True)) -> x (x, (BVal False)) -> BVal False _ -> And x' y' simplValue (Not x) = let x' = simplValue x in case x' of (BVal True) -> BVal False (BVal False) -> BVal True _ -> x' simplValue v = v instance Pretty Type where pretty (Pointer t) = pretty t <> text "*" pretty SpaceType = text spacetype pretty Int = text "int" pretty Bool = text "bool" pretty (Union fields) = text "union" <+> text "{" $+$ nest 2 (vcat [pretty ty <+> text f <> text ";" | (ty,f) <- fields]) $+$ text "}" pretty (SType (Struct name fields)) = text name pretty (THook str) = text str instance Pretty Value where pretty = pretty_ . simplValue where pretty_ (Cond c t e) = pretty c <+> text "?" <+> pretty t <+> text ":" <+> pretty e pretty_ Base = text "" pretty_ Null = text "NULL" pretty_ (IVal i) = int $ fromInteger $ toInteger i pretty_ (BVal True) = text "true" pretty_ (BVal False) = text "false" pretty_ (Abs x) = text "abs" <> parens (pretty_ x) pretty_ RootSpace = text "root" pretty_ (Minus v1 v2) = pretty_ v1 <+> text "-" <+> pretty_ v2 pretty_ (Plus v1 v2) = pretty_ v1 <+> text "+" <+> pretty_ v2 pretty_ (Div v1 v2) = parens (pretty_ v1) <+> text "/" <+> parens (pretty_ v2) pretty_ (Mod v1 v2) = parens (pretty_ v1) <+> text "%" <+> parens (pretty_ v2) pretty_ (Var x) = text x pretty_ (Clone x) = text ("static_cast<" ++ spacetype ++ "*>(") <> pretty_ x <> text "->clone(true))" -- pretty_ (Clone x) = text ("static_cast<" ++ spacetype ++ "*>(") <> pretty_ x <> text "->clone(false))" pretty_ (Field r f) = text r <> text "." <> text f pretty_ (Field' r f) = pretty_ r <> text "." <> text f pretty_ (PField (Field' (Var _) "evalState") f) = text f pretty_ (PField r f) = pretty_ r <> text "->" <> text f pretty_ (Lt x y) = parens (pretty_ x) <+> text "<" <+> parens (pretty_ y) pretty_ (Gq x y) = parens (pretty_ x) <+> text ">=" <+> parens (pretty_ y) pretty_ (Gt x y) = parens (pretty_ x) <+> text ">" <+> parens (pretty_ y) pretty_ (Eq x y) = parens (pretty_ x) <+> text "==" <+> parens (pretty_ y) pretty_ BaseContinue = text "! queue->empty()" pretty_ (And x y) = parens (pretty x) <+> text "&&" <+> parens (pretty y) pretty_ (Or x y) = parens (pretty x) <+> text "||" <+> parens (pretty y) pretty_ (Not x) = text "!" <> parens (pretty x) pretty_ (VHook s) = text s pretty_ (Max x y) = text "max" <> parens (pretty x <> text "," <> pretty y) -- pretty_ (CVar vs s i) = pretty_ s <> text "->" <> text vs <> text "()" <> brackets (pretty i) pretty_ (CVar vs s i) = pretty_ s <> text "->getVar" <> parens (text "$ARR_" <> text vs <> brackets (pretty i)) pretty_ (XVar vs s i) = pretty_ s <> text "->getVar" <> parens (text "$ARR_" <> text vs <> brackets (text i)) pretty_ (MinDom v) = pretty_ v <> text ".min()" pretty_ (MaxDom v) = pretty_ v <> text ".max()" pretty_ (SizeDom v) = pretty_ v <> text ".size()" pretty_ (Degree v) = pretty_ v <> text ".degree()" pretty_ (WDegree v) = pretty_ v <> text ".afc()" -- aka accumulated failure count pretty_ (UbRegret v) = pretty_ v <> text ".regret_max()" pretty_ (LbRegret v) = pretty_ v <> text ".regret_min()" pretty_ (Median v) = pretty_ v <> text ".med()" pretty_ Random = text "rand()" pretty_ (New (Struct name _)) = text "new" <+> text name pretty_ (Assigned var) = pretty_ var <> text ".assigned()" data Constraint = EqC Value Value | NqC Value Value | LtC Value Value | LqC Value Value | GtC Value Value | GqC Value Value ($==) = EqC ($/=) = NqC ($<) = LtC ($<=) = LqC ($>) = GtC ($>=) = GqC neg (EqC x y) = NqC x y neg (NqC x y) = EqC x y neg (LtC x y) = GqC x y neg (LqC x y) = GtC x y neg (GtC x y) = LqC x y neg (GqC x y) = LtC x y instance Pretty Constraint where pretty (EqC x y) = pretty x <> text "," <> text "IRT_EQ" <> text "," <> pretty y pretty (NqC x y) = pretty x <> text "," <> text "IRT_NQ" <> text "," <> pretty y pretty (LtC x y) = pretty x <> text "," <> text "IRT_LE" <> text "," <> pretty y pretty (LqC x y) = pretty x <> text "," <> text "IRT_LQ" <> text "," <> pretty y pretty (GtC x y) = pretty x <> text "," <> text "IRT_GR" <> text "," <> pretty y pretty (GqC x y) = pretty x <> text "," <> text "IRT_GQ" <> text "," <> pretty y data Statement = IfThenElse Value Statement Statement | Push Value | Skip | Update Value Value | Seq Statement Statement | Assign Value Value | Abort | Print Value [String] | SHook String | Post Value Constraint | Fold String Value Value Value (Value -> Value) (Value -> Value -> Value) | IFold String Value Value Value (Value -> Value) (Value -> Value -> Value) | MFold String [(Value, Value->Value)] ([Value] -> [Value] -> Value) | Delete Value dec var = Update var (var - 1) inc var = Update var (var + 1) (>>>) = Seq (<==) = Update assign = flip Update ifthen c t = IfThenElse c t Skip seqs = foldr (>>>) Skip instance Pretty Statement where pretty (Push tstate) = text "queue->push_front" <> parens (pretty tstate) <> text ";" pretty (IfThenElse c t e) = let c' = simplValue c in case c' of BVal True -> pretty t BVal False -> pretty e c -> case e of Skip -> text "if" <+> parens (pretty c) <+> text "{" $+$ nest 2 (pretty t) $+$ text "}" _ -> text "if" <+> parens (pretty c) <+> text "{" $+$ nest 2 (pretty t) $+$ text "} else {" $+$ nest 2 (pretty e) $+$ text "}" pretty Skip = empty pretty (Update var (Minus val 1)) | var == val = pretty var <> text "--;" pretty (Update var (Plus val 1)) | var == val = pretty var <> text "++;" pretty (Update var val) = pretty var <+> text "=" <+> pretty val <> text ";" pretty (Seq s1 s2) = pretty s1 $+$ pretty s2 pretty (Assign x Null) = pretty x pretty (Assign x y) = pretty x <+> text "=" <+> pretty y <> text ";" pretty Abort = text "break;" pretty (Print space vs) = (vcat $ map (\s -> text ("std::cout << \"[\"; for (int i=0; i<$ARR_" ++ s ++ ".size(); i++) { std::cout << ") <> pretty (XVar s space "i") <> text " << \" \"; }; std::cout << \"] \";") vs) <> text "std::cout << std::endl;" pretty (SHook s) = text s pretty (Post space c) = text "rel(*" <> parens (pretty space) <> text "," <> pretty c <> text ");" pretty (Fold vars state space m0 metric better) = let pos = Field' state "pos" size = VHook $ render $ text "$ARR_" <> text vars <> text ".size()" in text "int best_pos = -1;" $+$ pretty (Update pos 0) $+$ text "for (int metric = " <> pretty m0 <> text "; " <> pretty (pos @< size ) <> text "; " <> pretty pos <> text "++) {" $+$ nest 2 (text "if" <+> parens (text "!" <> pretty (CVar vars space pos) <> text ".assigned()") <+> text "{" $+$ nest 2 ( text "int current_metric = " <> pretty (metric (CVar vars space pos)) <> text ";" $+$ pretty (IfThenElse (Var "current_metric" `better` Var "metric") (Update (Var "metric") (Var "current_metric") >>> (Update (Var "best_pos") pos)) Skip ) ) $+$ text "}" ) $+$ text "}" $+$ pretty (Update pos (Var "best_pos")) pretty (IFold vars state space m0 metric better) = let pos = Field' state "pos" size = VHook $ render $ text "$ARR_" <> text vars <> text ".size()" in text "int best_pos = -1;" $+$ pretty (Update pos 0) $+$ text "for (int metric = " <> pretty m0 <> text "; " <> pretty (pos @< size ) <> text "; " <> pretty pos <> text "++) {" $+$ nest 2 (text "if" <+> parens (text "!" <> pretty (CVar vars space pos) <> text ".assigned()") <+> text "{" $+$ nest 2 ( text "int current_metric = " <> pretty (metric pos) <> text ";" $+$ pretty (IfThenElse (Var "current_metric" `better` Var "metric") (Update (Var "metric") (Var "current_metric") >>> (Update (Var "best_pos") pos)) Skip ) ) $+$ text "}" ) $+$ text "}" $+$ pretty (Update pos (Var "best_pos")) pretty (MFold state metrics better) = let space = Field "estate" "space" pos = Field state "pos" cvar = CVar "get" space pos size = VHook $ render $ pretty space <> text "->" <> text "get" <> text "().size()" acc_vars = [Var $ "metric" ++ show i | i <- [1..length metrics]] cur_vars = [Var $ "current_metric" ++ show i | i <- [1..length metrics]] init_list = hcat $ punctuate comma [pretty v <+> text "=" <+> pretty z | (v,(z,_)) <- zip acc_vars metrics] computations = vcat $ [text "int" <+> pretty (Update var (f cvar))| (var,(_,f)) <- zip cur_vars metrics] updates = foldl (>>>) Skip [Update v1 v2 | (v1,v2) <- zip acc_vars cur_vars] in text "int best_pos = -1;" $+$ pretty (Update pos 0) $+$ text "for (int " <> init_list <> text "; " <> pretty (pos @< size ) <> text "; " <> pretty pos <> text "++) {" $+$ nest 2 (text "if" <+> parens (text "!" <> pretty cvar <> text ".assigned()") <+> text "{" $+$ nest 2 ( computations $+$ pretty (IfThenElse (cur_vars `better` acc_vars) (updates >>> (Update (Var "best_pos") pos)) Skip ) ) $+$ text "}" ) $+$ text "}" $+$ pretty (Update pos (Var "best_pos")) pretty (Delete value) = text "delete" <+> pretty value <> text ";"