hahp 0.1.2 → 0.1.3
raw patch · 13 files changed
+168/−49 lines, 13 filesdep +random
Dependencies added: random
Files
- hahp-example/Main.hs +7/−4
- hahp.cabal +4/−2
- src/HAHP/Algorithm.hs +14/−15
- src/HAHP/Algorithm/Consistency.hs +2/−1
- src/HAHP/Algorithm/PriorityVector.hs +3/−1
- src/HAHP/Algorithm/Ranking.hs +5/−3
- src/HAHP/Data.hs +10/−0
- src/HAHP/Generator.hs +75/−0
- src/HAHP/Reporting.hs +2/−2
- src/HAHP/Sample/CarChoice.hs +2/−2
- src/HAHP/Sample/LeaderChoice.hs +2/−2
- src/HAHP/Validation/Alternatives.hs +12/−17
- src/HAHP/Validation/Unique.hs +30/−0
hahp-example/Main.hs view
@@ -3,6 +3,7 @@ import Data.Time import HAHP.Algorithm import HAHP.Data+import HAHP.Generator import HAHP.Reporting import HAHP.Sample.Config1 import HAHP.Sample.Config2@@ -19,8 +20,10 @@ --, (sampleAHPConfig2, sampleAlternatives2) --, (sampleAHPConfig3, sampleAlternatives3) --, (smeConfig, smeAlternatives)- (leaderChoiceTree, leaderChoiceAlternatives)- , (carChoiceTree, carChoiceAlternatives)+ --, (leaderChoiceTree, leaderChoiceAlternatives)+ --, (carChoiceTree, carChoiceAlternatives)+ generateDataSet $ GeneratorParameters True 3 3 100+ ,generateDataSet $ GeneratorParameters False 3 3 100 ] time <- getCurrentTime@@ -28,5 +31,5 @@ putStrLn "" mapM_ (putStrLn . simpleAHPSummary) inputDataSets -simpleAHPSummary :: (AHPTree, [Alternative]) -> String-simpleAHPSummary (ahpTree, alts) = simpleSummary $ simpleAHP ahpTree alts+simpleAHPSummary :: AHPDataSet -> String+simpleAHPSummary dataSet = simpleSummary . simpleAHP $ dataSet
hahp.cabal view
@@ -2,7 +2,7 @@ -- see http://haskell.org/cabal/users-guide/ name: hahp-version: 0.1.2+version: 0.1.3 synopsis: Analytic Hierarchy Process description: Analytic Hierarchy Process implementation. license: AGPL-3@@ -22,7 +22,7 @@ library -- other-modules: -- other-extensions: - build-depends: base >=4.7 && <5 , containers, hmatrix, parallel, time+ build-depends: base >=4.7 && <5 , containers, hmatrix, parallel, random, time hs-source-dirs: src default-language: Haskell2010 exposed-modules:@@ -31,6 +31,7 @@ HAHP.Algorithm.PriorityVector HAHP.Algorithm.Ranking HAHP.Data+ HAHP.Generator HAHP.Reporting HAHP.Sample.Config1 HAHP.Sample.Config2@@ -40,6 +41,7 @@ HAHP.Sample.SquareMatrixError HAHP.Validation.Alternatives HAHP.Validation.Tree+ HAHP.Validation.Unique executable hahp-example main-is: Main.hs
src/HAHP/Algorithm.hs view
@@ -14,18 +14,18 @@ -- |This function is a quick way to rank a set of alternatives with AHP algorithm. -- This function call everithing required to configure an execute AHP process. -- If something goes wrong, an error is raised.-simpleAHP :: AHPTree- -> [Alternative]- -> (AHPTree, [Alternative], [TreeError], [AlternativesError])-simpleAHP ahpTree alts =+simpleAHP :: AHPDataSet+ -> (AHPDataSet, [TreeError], [AlternativesError])+simpleAHP inputDataSet = if null inputTreeErrors && null altsErrors- then (completeTree, ranking, treeErrors, [])- else (ahpTree, alts, inputTreeErrors ++ treeErrors, altsErrors)- where initializedTree = initAHP ahpTree- (completeTree, ranking) = rankAlternatives initializedTree alts+ then (processedDataSet, treeErrors, [])+ else (inputDataSet, inputTreeErrors ++ treeErrors, altsErrors)+ where (ahpTree, alts) = inputDataSet+ initializedTree = initAHP ahpTree+ processedDataSet = rankAlternatives (initializedTree, alts) --- inputTreeErrors = validateInputAHPTree ahpTree- altsErrors = validateAlternatives ahpTree alts+ altsErrors = validateAlternatives inputDataSet treeErrors = if null inputTreeErrors then validateAHPTree initializedTree else []@@ -38,13 +38,12 @@ -- * Part 2 = dynamic part -rankAlternatives :: AHPTree- -> [Alternative]- -> (AHPTree, [Alternative])-rankAlternatives ahpTree alts = (rankedAhpTree, reverse sortedRankedAlternatives)- where ranks = concat . toLists . fromJust $ alternativesPriority rankedAhpTree+rankAlternatives :: AHPDataSet+ -> AHPDataSet+rankAlternatives (ahpTree, alts) = (rankedAhpTree, sortedRankedAlternatives)+ where ranks = concat . toLists . fromJust . alternativesPriority $ rankedAhpTree rankedAhpTree = computeTreeAlternativesPriorities alts ahpTree- sortedRankedAlternatives = map fst . sortOn' snd $ zip alts ranks+ sortedRankedAlternatives = reverse . map fst . sortOn' snd $ zip alts ranks -- | Sort a list by comparing the results of a key function applied to each -- element. @sortOn f@ is equivalent to @sortBy . comparing f@, but has the
src/HAHP/Algorithm/Consistency.hs view
@@ -3,6 +3,7 @@ computeTreeConsistencies ) where +import Control.Parallel.Strategies import HAHP.Data import Numeric.LinearAlgebra.HMatrix @@ -13,7 +14,7 @@ case ahpTree of (AHPTree _ prefMat _ _ _ children) -> ahpTree { consistencyValue = Just $ matrixConsistency prefMat- , children = map computeTreeConsistencies children+ , children = parMap rseq computeTreeConsistencies children } AHPLeaf {} -> ahpTree
src/HAHP/Algorithm/PriorityVector.hs view
@@ -4,6 +4,7 @@ priorityVector ) where +import Control.Parallel.Strategies import HAHP.Data import Numeric.LinearAlgebra.HMatrix @@ -12,7 +13,8 @@ case ahpTree of (AHPTree _ prefMat _ _ _ children) -> ahpTree { childrenPriority = Just $ priorityVector prefMat- , children = map computeTreePriorityVectors children+ , children = parMap rseq computeTreePriorityVectors children+ --, children = map computeTreePriorityVectors children } AHPLeaf {} -> ahpTree
src/HAHP/Algorithm/Ranking.hs view
@@ -1,5 +1,6 @@ module HAHP.Algorithm.Ranking where +import Control.Parallel.Strategies import Data.List import qualified Data.Map as M import Data.Maybe@@ -25,14 +26,14 @@ computeChildrenTreeAlternativesPriorities :: [Alternative] -> AHPTree -> AHPTree computeChildrenTreeAlternativesPriorities alts ahpTree = ahpTree {- children = map (computeTreeAlternativesPriorities alts) (children ahpTree)+ children = parMap rseq (computeTreeAlternativesPriorities alts) (children ahpTree) } -- * Computation function agregatePriorities :: AHPTree -> PriorityVector agregatePriorities ahpTree = catChildVectors <> childPriorities- where childVectors = map (fromJust . alternativesPriority) (children ahpTree)+ where childVectors = parMap rseq (fromJust . alternativesPriority) (children ahpTree) catChildVectors = foldl1 (|||) childVectors childPriorities = fromJust . childrenPriority $ ahpTree @@ -43,8 +44,9 @@ buildAlternativePairwiseMatrix :: AHPTree -> [Alternative] -> Matrix Double buildAlternativePairwiseMatrix ahpTree alts = (length alts >< length alts) matrix- where vals = map (selectIndValue (name ahpTree)) alts+ where vals = parMap rseq (selectIndValue (name ahpTree)) alts cartesianProduct = [(x, y) | x <- vals, y <- vals]+ -- matrix = parMap rseq operator cartesianProduct matrix = map operator cartesianProduct operator = if maximize ahpTree -- `uncurry` permit the use of an operator on a pair
src/HAHP/Data.hs view
@@ -3,6 +3,16 @@ import Data.Map (Map) import Numeric.LinearAlgebra.HMatrix +-- * Data set macro type++type AHPDataSet = (AHPTree, [Alternative])++data GeneratorParameters = GeneratorParameters { randomSize :: Bool+ , maxTreeLevels :: Int+ , maxLevelChildren :: Int+ , maxAlternatives :: Int+ }+ -- * AHP tree definition data AHPTree = AHPTree { name :: String
+ src/HAHP/Generator.hs view
@@ -0,0 +1,75 @@+module HAHP.Generator where++import Data.List (insert)+import Data.Map (empty, singleton, fromList)+import HAHP.Data+import Numeric.LinearAlgebra.Data (ident, (><))+import System.IO.Unsafe+import System.Random++-- * Data set generator++generateDataSet :: GeneratorParameters+ -> AHPDataSet+generateDataSet params = (ahpTree, alternatives)+ where ahpTree = generateAHPTree params+ alternatives = generateAlternatives params ahpTree++-- * AHP tree generator++generateAHPTree :: GeneratorParameters+ ->AHPTree+generateAHPTree params = generateAHPTree' params levels []+ where levels = if randomSize params+ then unsafeRandomRIO (1, maxTreeLevels params)+ else maxTreeLevels params++generateAHPTree' :: GeneratorParameters+ -> Int+ -> [Int]+ -> AHPTree+generateAHPTree' params maxlevels parentIndexes = if (length parentIndexes) + 1 >= maxlevels+ then AHPLeaf treeName True Nothing+ else AHPTree { name = treeName+ , preferenceMatrix = generateMatrix (childNum)+ , consistencyValue = Nothing+ , childrenPriority = Nothing+ , alternativesPriority = Nothing+ , children = children+ }+ where treeName = if null parentIndexes+ then "Global Objective"+ else "Node " ++ (concatMap (\x -> show x ++ ".") parentIndexes)+ childNum = if randomSize params+ then unsafeRandomRIO (1, maxLevelChildren params)+ else maxLevelChildren params+ children = take childNum $ map (\x -> generateAHPTree' params maxlevels (parentIndexes ++ [x])) [1..]++generateMatrix :: Int+ -> PairwiseMatrix+generateMatrix size = (size><size) $ repeat 1++-- * Alternatives generator++generateAlternatives :: GeneratorParameters+ -> AHPTree+ -> [Alternative]+generateAlternatives params ahpTree = take altsNum randomAlts+ where altsNum = if randomSize params+ then unsafeRandomRIO (1, maxAlternatives params)+ else maxAlternatives params+ inds = map name . getTreeLeaves $ ahpTree+ randomAlts = map (generateAlternative inds) [1..]++generateAlternative :: [IndicatorName]+ -> Int+ -> Alternative+generateAlternative indNames index = Alternative name values+ where name = "Alternative " ++ show index+ values = fromList $ zip indNames randomValues+ randomValues = unsafePerformIO . sequence . replicate (length indNames) . randomRIO $ (1, 100)++-- * Tools++unsafeRandomRIO :: (Random a) => (a, a) -> a+unsafeRandomRIO range = unsafePerformIO . randomRIO $ range
src/HAHP/Reporting.hs view
@@ -21,9 +21,9 @@ ] -- | Print a simple report about an AHP tree and ranking result-simpleSummary :: (AHPTree, [Alternative], [TreeError], [AlternativesError]) -- ^ AHP tree, some alternatives and the result of tree validation+simpleSummary :: (AHPDataSet, [TreeError], [AlternativesError]) -- ^ AHP tree, some alternatives and the result of tree validation -> String -- ^ Report build from input-simpleSummary (ahpTree, alts, treeErrors, altsErrors) = treeSummary ++ altSummary ++ errorSummary ++ "\\newpage \n"+simpleSummary ((ahpTree, alts), treeErrors, altsErrors) = treeSummary ++ altSummary ++ errorSummary ++ "\\newpage \n" where treeSummary = showConfiguration ahpTree altSummary = showAlternatives alts errorSummary = showErrors treeErrors altsErrors
src/HAHP/Sample/CarChoice.hs view
@@ -1,7 +1,7 @@ module HAHP.Sample.CarChoice where -import Data.Map-import HAHP.Data+import Data.Map+import HAHP.Data import Numeric.LinearAlgebra.HMatrix carChoiceTree :: AHPTree
src/HAHP/Sample/LeaderChoice.hs view
@@ -1,7 +1,7 @@ module HAHP.Sample.LeaderChoice where -import Data.Map-import HAHP.Data+import Data.Map+import HAHP.Data import Numeric.LinearAlgebra.HMatrix leaderChoiceTree :: AHPTree
src/HAHP/Validation/Alternatives.hs view
@@ -6,44 +6,39 @@ import HAHP.Data import HAHP.Validation.Unique -validateAlternatives :: AHPTree- -> [Alternative]+validateAlternatives :: AHPDataSet -> [AlternativesError]-validateAlternatives ahpTree alts = validate' ahpTree alts testsList+validateAlternatives dataSet = validate' dataSet testsList -validate' :: AHPTree- -> [Alternative]- -> [AHPTree -> [Alternative] -> Maybe AlternativesError]+validate' :: AHPDataSet+ -> [AHPDataSet -> Maybe AlternativesError] -> [AlternativesError]-validate' ahpTree alts checks = catMaybes $ parMap rseq (\check -> check ahpTree alts) checks+validate' dataSet checks = catMaybes $ parMap rseq (\check -> check dataSet) checks -testsList :: [AHPTree -> [Alternative] -> Maybe AlternativesError]+testsList :: [AHPDataSet -> Maybe AlternativesError] testsList = [ noAlternativesTest , alternativesUnicityTest , indicatorsValuesExistenceTest ] -noAlternativesTest :: AHPTree- -> [Alternative]+noAlternativesTest :: AHPDataSet -> Maybe AlternativesError-noAlternativesTest _ alts =+noAlternativesTest (_, alts) = if not . null $ alts then Nothing else Just NoAlternativesError -alternativesUnicityTest :: AHPTree- -> [Alternative]+alternativesUnicityTest :: AHPDataSet -> Maybe AlternativesError-alternativesUnicityTest _ alts =+alternativesUnicityTest (_, alts) = if null repeatedAlternativesNames then Nothing else Just AlternativesUnicityError {repeatedAlternativesNames = repeatedAlternativesNames} where repeatedAlternativesNames = repeated . map altName $ alts -indicatorsValuesExistenceTest :: AHPTree- -> [Alternative]+indicatorsValuesExistenceTest :: AHPDataSet -> Maybe AlternativesError-indicatorsValuesExistenceTest ahpTree alts =+indicatorsValuesExistenceTest (ahpTree, alts) = if null errors then Nothing else Just IndicatorsValuesExistenceError { indValuesErrors = errors}
+ src/HAHP/Validation/Unique.hs view
@@ -0,0 +1,30 @@+module HAHP.Validation.Unique where++--import Data.List.Unique+import Data.List (group, sort, sortBy)++-- * Unique++-- TO REMOVE+-- https://hackage.haskell.org/package/Unique-0.4.2/docs/src/Data-List-Unique.html#repeated++sg :: Ord a => [a] -> [[a]]+sg = group . sort++filterByLength :: Ord a => (Int -> Bool) -> [a] -> [[a]]+filterByLength p = filter (p . length) . sg++-- | 'repeated' finds only the elements that are present more than once in the list. Example:+--+-- > repeated "foo bar" == "o"++repeated :: Ord a => [a] -> [a]+repeated = repeatedBy (>1)++-- | The repeatedBy function behaves just like repeated, except it uses a user-supplied equality predicate.+--+-- > repeatedBy (>2) "This is the test line" == " eist"++repeatedBy :: Ord a => (Int -> Bool) -> [a] -> [a]+repeatedBy p = map head . filterByLength p+