Aelve Codesearch

grep over package repositories
penrose-0.1.1.1
src/Penrose/ShadowMain.hs
-- | Main module of the Penrose system (split out for testing; Main is the real main)
{-# LANGUAGE AllowAmbiguousTypes       #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE OverloadedStrings         #-}
{-# LANGUAGE QuasiQuotes               #-}
{-# LANGUAGE RankNTypes                #-}
{-# LANGUAGE UnicodeSyntax             #-}
{-# OPTIONS_HADDOCK prune #-}

module Penrose.ShadowMain
  ( shadowMain
  ) where

import qualified Control.Concurrent         as CC
import           Control.Exception
import           Control.Monad              (forM_, when)
import           Control.Monad.Trans
import           Data.Aeson
import qualified Data.ByteString.Lazy.Char8 as B
import qualified Data.List                  as L (intercalate)
import qualified Data.List.Split            as LS (splitOn)
import qualified Data.Map.Strict            as M
import qualified Data.Text.Lazy             as T
import           Data.Text.Lazy.Encoding    (decodeUtf8)
import           Data.Version               (showVersion)
import           Debug.Trace
import           Network.HTTP.Types.Status
import           Paths_penrose              (version)
import           Penrose.API
import qualified Penrose.Element            as D
import qualified Penrose.Env                as E
import qualified Penrose.GenOptProblem      as G
import qualified Penrose.Optimizer          as O
import           Penrose.Plugins
import qualified Penrose.Server             as Server
import qualified Penrose.Style              as S
import qualified Penrose.Substance          as C
import qualified Penrose.Sugarer
import           Penrose.Util
import           Prelude                    hiding (catch)
import           System.Console.Docopt
import           System.Console.Pretty      (Color (..), Style (..), bgColor,
                                             color, style, supportsPretty)
import           System.Environment
import           System.Exit
import           System.IO
import           System.IO.Error            hiding (catch)
import qualified Text.Megaparsec            as MP (parseErrorPretty, runParser)
import           Text.Show.Pretty
import           Web.Scotty

default (Int, Float)

-- when false, executes headless for profiling
useFrontend :: Bool
useFrontend = True

argPatterns :: Docopt
argPatterns = [docoptFile|USAGE.txt|]

getArgOrExit = getArgOrExitWith argPatterns

-- | `shadowMain` runs the Penrose system
shadowMain :: IO ()
shadowMain = do
  args <- parseArgsOrExit argPatterns =<< getArgs
  if args `isPresent` longOption "version"
    then do
      putStrLn $ showVersion version
      return ()
    else do
      domain <- args `getArgOrExit` longOption "domain"
      port <- args `getArgOrExit` longOption "port"
      config <- args `getArgOrExit` longOption "config"
      if args `isPresent` command "editor"
        then let isVerbose = args `isPresent` longOption "verbose"
             in Server.serveEditor domain (read port) isVerbose
        else do
          subFile <- args `getArgOrExit` argument "substance"
          styFile <- args `getArgOrExit` argument "style"
          elementFile <- args `getArgOrExit` argument "element"
          penroseRenderer subFile styFile elementFile domain config $ read port

penroseRenderer ::
     String -> String -> String -> String -> String -> Int -> IO ()
penroseRenderer subFile styFile elementFile domain configPath port = do
  subIn <- readFile subFile
  styIn <- readFile styFile
  elementIn <- readFile elementFile
  initState <-
    case compileTrio subIn styIn elementIn of
      Left err     -> error $ show err
      Right (s, _) -> return s
  -- Read optimization config and so it can be included in the initial state
  configStr <- B.readFile configPath
  let configBstr = decode configStr :: Maybe G.OptConfig
  let optConfig =
        case configBstr of
          Nothing -> error "couldn't read opt config JSON"
          Just x  -> x
  putStrLn "Opt config:\n"
  print optConfig
  let state = initState {G.oConfig = optConfig}
  if useFrontend
    then Server.serveRenderer domain port state
    else let numTrials = 1000
         in let res = map (\x -> stepsWithoutServer state) [1 .. numTrials]
            in print $ map G.varyingState res -- Needed so all of res is evaluated, but don't spend so much time prettyprinting

stepsWithoutServer :: G.State -> G.State
stepsWithoutServer initState =
  let (finalState, numSteps) =
        head $ dropWhile notConverged $ iterate stepAndCount (initState, 0)
  in trace ("\nnumber of outer steps: " ++ show numSteps) $ finalState
  where
    stepAndCount (s, n) = (O.step s, n + 1)
    notConverged (s, n) =
      G.optStatus (G.paramsr s) /= G.EPConverged && n < maxSteps
    maxSteps = 10 ** 3 -- Not sure how many steps it usually takes to converge