packages feed

chemical-equation-0.0: src/Main.hs

module Main where

import Common

import qualified RowEchelon

import qualified Data.Array.Comfort.Boxed as Array
import qualified Data.Foldable as Fold
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.List.HT as ListHT
import qualified Data.List as List
import qualified Data.Ratio as Ratio
import Data.Array.Comfort.Boxed (Array)
import Data.Set (Set)
import Data.Ratio ((%))

import qualified Shell.Utility.Verbosity as Verbosity

import System.Environment (getArgs)



matrixFromReactantSet ::
   Set Reactant -> Array (Set String, Set Reactant) Rational
matrixFromReactantSet reactantSet =
   let elements = foldMap Map.keysSet reactantSet
   in Array.fromAssociations 0 (elements, reactantSet) $ do
         r <- Set.toList reactantSet
         (e,n) <- Map.toList r
         return ((e,r), fromInteger n)


gcdRat :: Rational -> Rational -> Rational
gcdRat x y =
   gcd (Ratio.numerator x) (Ratio.numerator y)
   %
   lcm (Ratio.denominator x) (Ratio.denominator y)

integerFromRational :: Rational -> Integer
integerFromRational r =
   let n = round r in
   if r == n%1 then n else error "gcdRat failed"

normalizeRationalVector :: (Functor f, Foldable f) => f Rational -> f Integer
normalizeRationalVector v =
   let d = Fold.foldl gcdRat 0 v
   in fmap (integerFromRational . (/d)) v



main :: IO ()
main = do
   let verbosity = Verbosity.normal
   (reactantSet,reactantsWithoutDuplicates)
      <- preprocessArguments verbosity =<< getArgs

   let mat = matrixFromReactantSet reactantSet
   let sols =
         map (Map.fromList . zip (Set.toAscList reactantSet)) $
         List.transpose $ RowEchelon.matrixRows $
         RowEchelon.nullspace $
         RowEchelon.matrixFromRows $
         ListHT.sliceVertical (Set.size reactantSet) $
         Array.toList mat

   displaySolutions verbosity reactantsWithoutDuplicates $
      map normalizeRationalVector sols