module Main where
import Common
import qualified FLINT.Utility as F
import qualified FLINT.MatrixInteger as FmpzMat
import qualified FLINT.Type as FLINT
import FLINT.Example ()
import Foreign.Ptr (Ptr)
import qualified Data.Array.Comfort.Shape as Shape
import qualified Data.Traversable as Trav
import qualified Data.Foldable as Fold
import qualified Data.Map as Map
import qualified Data.Set as Set
import Data.Set (Set)
import qualified Options.Applicative as OP
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Cont (ContT(ContT), evalContT)
matrixFromReactantSet :: Set Reactant -> ContT r IO (Ptr FLINT.Matrix)
matrixFromReactantSet reactantSet = do
let elements = foldMap Map.keysSet reactantSet
mat <-
ContT $
F.withMatrix
(fromIntegral $ Set.size elements)
(fromIntegral $ Set.size reactantSet)
liftIO $ do
FmpzMat.zero mat
Fold.for_ (zip [0..] $ Set.toAscList reactantSet) $ \(j,reactant) ->
Fold.sequence_ $ flip Map.mapWithKey reactant $ \element n -> do
let i = fromIntegral $ Shape.offset elements element
ptr <- FmpzMat.entry mat i j
F.integerFlintFromPrelude ptr n
return mat
{- |
The solution consists essentially of calling 'FmpzMat.nullspace'.
All the Haskell code is needed for transferring data
between FLINT and Haskell data structures,
parsing and validating arguments and presenting the results.
-}
main :: IO ()
main = do
(verbosity,format,args) <- OP.execParser $ info parser
(reactantSet,reactantsWithoutDuplicates)
<- preprocessArguments verbosity args
sols <- evalContT $ do
mat <- matrixFromReactantSet reactantSet
n <- liftIO $ FmpzMat.ncols mat
nullBasis <- ContT $ F.withMatrix n n
nullspaceDim <- liftIO $ FmpzMat.nullspace nullBasis mat
let reactantIndices = Map.fromList $ zip (Set.toAscList reactantSet) [0..]
liftIO $
Trav.for [0 .. nullspaceDim-1] $ \j ->
Trav.for reactantIndices $ \i ->
F.integerPreludeFromFlint =<< FmpzMat.entry nullBasis i j
displaySolutions verbosity format reactantsWithoutDuplicates $
map cancelIntegerVector sols