{-# LANGUAGE GADTs, MultiParamTypeClasses, OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables, UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses, ViewPatterns #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
module SingularBridge (singIdealFun, singPolyFun) where
import Algebra.Internal
import Algebra.Ring.Ideal
import Algebra.Ring.Polynomial hiding (lex)
import Control.Applicative
import Data.Char
import Data.List
import Data.Maybe (fromMaybe, mapMaybe)
import qualified Data.Text as T
import Numeric
import Numeric.Field.Fraction
import System.IO.Unsafe
import System.Process
class IsStrongMonomialOrder ord => SingularOrder ord where
singularOrder :: p ord -> String
instance SingularOrder Lex where
singularOrder _ = "lp"
instance SingularOrder Grevlex where
singularOrder _ = "dp"
idealProgram :: forall ord n. (SingularOrder ord, KnownNat n)
=> String
-> Ideal (OrderedPolynomial (Fraction Integer) ord n)
-> String
idealProgram fun ideal =
withStrongMonomialOrder (Proxy :: Proxy ord) (sing :: SNat n) $
let vars = generate sing $ \i -> "x(" ++ show (fromEnum i) ++ ")"
istr = intercalate ", " $ map (showPolynomialWith vars 5) $ generators ideal
in (++";") $ intercalate ";\n"
[ "LIB \"primdec.lib\""
, "LIB \"f5_library.lib\""
, "ring R = 0,(x(0.." ++ show (sNatToInt (sing :: SNat n) - 1) ++ "))," ++ singularOrder (Proxy :: Proxy ord)
, "ideal I = " ++ istr
, "option(redSB)"
, "print(" ++ fun ++ "(I))"
, "exit"
]
singular :: String -> IO String
singular code = readProcess "singular" ["-q"] code
readSingularIdeal :: (KnownNat n, IsStrongMonomialOrder ord)
=> SNat n -> Proxy ord -> String -> [OrderedPolynomial (Fraction Integer) ord n]
readSingularIdeal n p (T.pack -> code) =
mapMaybe (readSingularPoly n p . T.unpack) $ map (\a -> fromMaybe a $ T.stripSuffix "," a) $ T.lines code
readSingularPoly :: (KnownNat n, IsStrongMonomialOrder ord)
=> SNat n -> Proxy ord -> String -> Maybe (OrderedPolynomial (Fraction Integer) ord n)
readSingularPoly n pxy code =
withStrongMonomialOrder pxy n $
case [p | (p, xs) <- readPoly code, all isSpace xs] of
(p:_) -> Just p
_ -> Nothing
where
readPoly st = do
(t, rest) <- readTerm st
readPoly' rest t
readPoly' st acc = do ("+", st') <- lex st
(t, rest) <- readTerm st'
readPoly' rest (acc + t)
<|> do ("-", st') <- lex st
(t, rest) <- readTerm st'
readPoly' rest (acc - t)
<|> return (acc, st)
readCoeff st = do
(modify, st') <- do { ("-", roo) <- lex st ; return (negate, roo) } <|> return (id, st)
(num, rest) <- readDec st'
(a, foo) <- lex rest
case a of
"/" -> do
(den, rest') <- readDec foo
return (injectCoeff $ modify $ num % den, rest')
_ -> return (injectCoeff $ modify $ num % 1, rest)
readTerm st = do
(a, rest) <- readFactor st
(ts, gomi) <- readTerm' rest
return (product (a : ts), gomi)
readTerm' st = do ("*", st') <- lex st
(a, rest) <- readFactor st'
(as, gomi) <- readTerm' rest
return (a: as, gomi)
<|> return ([], st)
readFactor st = readCoeff st <|> readVar st
readVar st = do
("x", '(':rest) <- lex st
(nstr, ')':mpow) <- lex rest
(nth, "") <- readDec nstr
(power, gomi) <- do ("^", rst'') <- lex mpow
(pow, gomi) <- readDec rst''
return (pow :: Integer, gomi)
<|> return (1, mpow)
return (var (toEnum nth) ^ power, gomi)
singIdealFun :: forall ord n. (SingularOrder ord, KnownNat n)
=> String -> Ideal (OrderedPolynomial (Fraction Integer) ord n) -> Ideal (OrderedPolynomial (Fraction Integer) ord n)
singIdealFun fun ideal =
withStrongMonomialOrder (Proxy :: Proxy ord) (sing :: SNat n) $
unsafePerformIO $ do
ans <- singular $ idealProgram fun ideal
return $ toIdeal $ readSingularIdeal (sing :: SNat n) (Proxy :: Proxy ord) ans
singPolyFun :: forall ord n. (SingularOrder ord, KnownNat n)
=> String
-> Ideal (OrderedPolynomial (Fraction Integer) ord n)
-> OrderedPolynomial (Fraction Integer) ord n
singPolyFun fun ideal = unsafePerformIO $ do
ans <- singular $ idealProgram fun ideal
let Just p = readSingularPoly (sing :: SNat n) (Proxy :: Proxy ord) ans
return p