exchangealgebra-0.6.0.0: test/Golden/ExampleNumbers/RippleAnalysis.hs
-- | Reproduce the coefficient matrix and analysis calls from the ripple example.
module Golden.ExampleNumbers.RippleAnalysis (numericRows) where
import Data.Array.IO (IOArray, getAssocs, newListArray)
import Data.List (foldl')
import qualified Data.Map.Strict as M
import Data.Word (Word64)
import GHC.Float (castDoubleToWord64)
import Numeric (showHex)
import System.Random (RandomGen (genWord32), StdGen, mkStdGen, randomR)
import ExchangeAlgebra.Simulation.Analysis (leontiefInverse, rippleEffect)
-- | The example's nine producing industries, excluding final demand.
type Industry = Int
-- | One coefficient, Leontief inverse entry, or ripple entry.
type NumericRow = (String, Industry, Industry, Word64, String)
-- | Reproduce the example's first term with seed 42 and in-house ratio 0.4.
coefficientColumns :: M.Map Industry [Double]
coefficientColumns = fst $ foldl' addColumn (M.empty, mkStdGen 42) [1 .. 10]
where
addColumn (columns, generator) industry =
let (samples, nextGenerator) = drawSamples generator
total = sum samples
coefficients = map (\sample -> sample / total * 0.4) samples
in (M.insert industry coefficients columns, nextGenerator)
drawSamples :: StdGen -> ([Double], StdGen)
drawSamples generator =
let (values, nextGenerator) = draw 9 (skipGenerator generator)
clipped = map (\value -> if value < 0.1 then 0 else value) values
in (clipped ++ [0], nextGenerator)
draw 0 generator = ([], generator)
draw remaining generator =
let (value, nextGenerator) = randomR (0, 1.0) generator
(values, finalGenerator) = draw (remaining - 1) nextGenerator
in (value : values, finalGenerator)
skipGenerator generator =
foldl' (\current _ -> snd (genWord32 current)) generator [1 .. 1000]
-- | Calculate the first-term input matrix, inverse, and ninth-industry ripple.
numericRows :: IO [NumericRow]
numericRows = do
let entries =
[ coefficient row column
| row <- [1 .. 9]
, column <- [1 .. 9]
]
matrix <- newListArray ((1, 1), (9, 9)) entries
:: IO (IOArray (Industry, Industry) Double)
inverse <- leontiefInverse matrix
ripple <- rippleEffect 9 inverse
coefficientRows <- pure $ zipWith (makeRow "inputCoefficient") indexes entries
inverseRows <- map (uncurry (makeRow "leontiefInverse")) <$> getAssocs inverse
rippleRows <- map (uncurry (makeRow "rippleEffect")) <$> getAssocs ripple
pure (coefficientRows ++ inverseRows ++ rippleRows)
where
indexes = [(row, column) | row <- [1 .. 9], column <- [1 .. 9]]
coefficient row column =
case M.lookup column coefficientColumns of
Just values -> case drop (row - 1) values of
value : _ -> value
[] -> 0
Nothing -> 0
makeRow name (row, column) value =
(name, row, column, castDoubleToWord64 value, show value)